efi/x86: confine type unsafe casting to mixed mode
Subsystems (5)
Ard Biesheuvel
maintainerv2 cover 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.
Changes since v1:
- Substantially more cleanup work to simplify and hide the mixed mode handling in generic EFI code.
- Get rid of all the pointless passing around of sys_table_arg
- Incorporate an updated version of Matthew's PCI DMA disable patch using EFI events to defer poking the busmaster bits until after all the ordinary ExitBootServices() callbacks have executed.
Code can be found here
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-x86-cleanup-v2
Ard Biesheuvel (20):
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: extend native protocol definitions with mixed_mode
aliases
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 32/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 efi/libstub: get rid of 'sys_table_arg' macro parameter efi/libstub: unify the efi_char16_printk implementations efi/libstub/x86: drop __efi_early() export of efi_config struct efi/libstub: drop sys_table_arg from printk routines efi/libstub: remove 'sys_table_arg' from all function prototypes efi/libstub: drop protocol argument from efi_call_proto() macro efi/libstub: drop 'table' argument from efi_table_attr() macro efi/libstub: use 'func' not 'f' as macro parameter efi/libstub: tidy up types and names of global cmdline variables efi/libstub: import type definitions for creating and signalling
events
Matthew Garrett (1):
efi: Allow disabling PCI busmastering on bridges during boot
.../admin-guide/kernel-parameters.txt | 4 + arch/arm/include/asm/efi.h | 17 +- arch/arm64/include/asm/efi.h | 16 +- arch/x86/Kconfig | 1 + arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/eboot.c | 180 ++-- arch/x86/boot/compressed/eboot.h | 30 +- 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 | 16 +- arch/x86/include/asm/efi.h | 76 +- arch/x86/platform/efi/efi.c | 12 +- arch/x86/platform/efi/efi_64.c | 6 +- arch/x86/platform/efi/quirks.c | 2 +- drivers/firmware/efi/Kconfig | 22 + drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/arm-stub.c | 98 ++- drivers/firmware/efi/libstub/arm32-stub.c | 40 +- drivers/firmware/efi/libstub/arm64-stub.c | 24 +- .../firmware/efi/libstub/efi-stub-helper.c | 226 +++-- drivers/firmware/efi/libstub/efistub.h | 35 +- drivers/firmware/efi/libstub/fdt.c | 53 +- drivers/firmware/efi/libstub/gop.c | 30 +- drivers/firmware/efi/libstub/pci.c | 116 +++ drivers/firmware/efi/libstub/random.c | 54 +- drivers/firmware/efi/libstub/secureboot.c | 6 +- drivers/firmware/efi/libstub/tpm.c | 23 +- include/linux/efi.h | 816 +++++++++--------- 29 files changed, 980 insertions(+), 1027 deletions(-) delete mode 100644 arch/x86/boot/compressed/efi_stub_32.S delete mode 100644 arch/x86/boot/compressed/efi_stub_64.S create mode 100644 drivers/firmware/efi/libstub/pci.c
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 1/21 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 v2 2/21 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 v2 3/21 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 ++------- include/linux/efi.h | 13 +++++++++++++ 3 files changed, 20 insertions(+), 16 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; status = efi_call_early(locate_handle,
@@ -164,14 +165,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 ;
@@ -266,6 +264,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,
@@ -283,13 +282,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,
include/linux/efi.h +13 -0
@@ -48,6 +48,19 @@ typedef u16 efi_char16_t; /* UNICODE character */typedef u64 efi_physical_addr_t ;typedef void *efi_handle_t ; +#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))[idx]) + +#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++) +/* * 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
Ard Biesheuvel
maintainerPATCH v2 4/21 efi/libstub: extend native protocol definitions with mixed_mode aliases
In reply to Ard BiesheuvelIn preparation of moving to a native vs. mixed mode split rather than a 32 vs. 64 bit split when it comes to invoking EFI firmware services, update all the native protocol definitions and redefine them as unions containing an anonymous struct for the native view and a struct called 'mixed_mode' describing the 32-bit view of the protocol when called from 64-bit code.
While at it, flesh out some PCI I/O member definitions that we will be needing shortly.
--- arch/x86/boot/compressed/eboot.h | 15 +- drivers/firmware/efi/libstub/arm-stub.c | 4 +- drivers/firmware/efi/libstub/random.c | 22 +- include/linux/efi.h | 506 +++++++++++++------- 4 files changed, 365 insertions(+), 182 deletions(-)
arch/x86/boot/compressed/eboot.h +11 -4
@@ -24,10 +24,17 @@ typedef struct { u64 blt; } efi_uga_draw_protocol_64_t; -typedef struct { -void *get_mode; -void *set_mode; -void *blt; +typedef union { +struct { +void *get_mode; +void *set_mode; +void *blt; + }; +struct { +u32 get_mode; +u32 set_mode; +u32 blt; + } mixed_mode; }efi_uga_draw_protocol_t ;#endif /* BOOT_COMPRESSED_EBOOT_H */
drivers/firmware/efi/libstub/arm-stub.c +2 -2
@@ -40,9 +40,9 @@ static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;void efi_char16_printk (efi_system_table_t *sys_table_arg,efi_char16_t *str) { -struct efi_simple_text_output_protocol *out; +efi_simple_text_output_protocol_t *out; - out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out; + out = (efi_simple_text_output_protocol_t *)sys_table_arg->con_out; out->output_string (out, str); }
drivers/firmware/efi/libstub/random.c +14 -8
@@ -9,7 +9,7 @@#include "efistub.h" -typedef struct efi_rng_protocol efi_rng_protocol_t ; +typedef union efi_rng_protocol efi_rng_protocol_t ; typedef struct { u32 get_info;
@@ -21,11 +21,17 @@ typedef struct {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 *); -efi_status_t (*get_rng)(struct efi_rng_protocol *, -efi_guid_t *,unsigned long ,u8 *out); +union efi_rng_protocol { +struct { +efi_status_t (*get_info)(efi_rng_protocol_t *, +unsigned long *,efi_guid_t *); +efi_status_t (*get_rng)(efi_rng_protocol_t *, +efi_guid_t *,unsigned long ,u8 *out); + }; +struct { +u32 get_info; +u32 get_rng; + } mixed_mode; }; efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg,
@@ -33,7 +39,7 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table_arg, {efi_guid_t rng_proto =EFI_RNG_PROTOCOL_GUID ;efi_status_t status; -struct efi_rng_protocol *rng =NULL ; +efi_rng_protocol_t *rng =NULL ; status =efi_call_early (locate_protocol, &rng_proto,NULL , (void **)&rng);
@@ -162,7 +168,7 @@ efi_status_t efi_random_get_seed(efi_system_table_t *sys_table_arg)efi_guid_t rng_proto =EFI_RNG_PROTOCOL_GUID ;efi_guid_t rng_algo_raw =EFI_RNG_ALGORITHM_RAW ;efi_guid_t rng_table_guid =LINUX_EFI_RANDOM_SEED_TABLE_GUID ; -struct efi_rng_protocol *rng =NULL ; +efi_rng_protocol_t *rng =NULL ;struct linux_efi_random_seed *seed =NULL ;efi_status_t status;
include/linux/efi.h +338 -168
594 lines not on this page · raw message
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 5/21 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/boot/compressed/eboot.c | 3 +- arch/x86/include/asm/efi.h | 35 +++++++++++--- drivers/firmware/efi/libstub/efi-stub-helper.c | 49 +++++++------------- include/linux/efi.h | 6 +-- 6 files changed, 51 insertions(+), 46 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/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)* 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. */ - romimage = (void *)(unsigned long )efi_table_attr (efi_pci_io_protocol, - romimage, pci); + romimage =efi_table_attr (efi_pci_io_protocol, romimage, pci); romsize =efi_table_attr (efi_pci_io_protocol, romsize, pci);if (!romimage || !romsize || romsize >SZ_16M )return EFI_INVALID_PARAMETER ;
arch/x86/include/asm/efi.h +28 -7
@@ -222,21 +222,42 @@ 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_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, ...) \ - __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 +17 -32
73 lines not on this page · raw message
include/linux/efi.h +3 -3
@@ -49,11 +49,11 @@ typedef u64 efi_physical_addr_t;typedef void *efi_handle_t ;#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])#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) \ for (i = 0; \
@@ -811,7 +811,7 @@ typedef struct {typedef union {struct {efi_guid_t guid; -unsigned long table; +void *table; };efi_config_table_32_t mixed_mode; }efi_config_table_t ;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 6/21 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) {
@@ -396,10 +389,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);
@@ -758,10 +748,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
@@ -822,6 +822,8 @@ typedef struct {unsigned long *ptr; } efi_config_table_type_t; +typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t ; +#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)#define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30))
@@ -873,7 +875,7 @@ typedef union {unsigned long con_in_handle;unsigned long con_in;unsigned long con_out_handle; -unsigned long con_out; +efi_simple_text_output_protocol_t *con_out;unsigned long stderr_handle;unsigned long stderr;efi_runtime_services_t *runtime;
@@ -1553,8 +1555,6 @@ typedef struct {u64 test_string; } efi_simple_text_output_protocol_64_t; -typedef union efi_simple_text_output_protocol efi_simple_text_output_protocol_t ; -union efi_simple_text_output_protocol {struct {void *reset;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 7/21 efi/libstub: drop explicit 32/64-bit protocol definitions
In reply to Ard BiesheuvelNow that we have incorporated the mixed mode protocol definitions into the native ones using unions, we no longer need the separate 32/64 bit struct definitions, with the exception of the EFI system table definition and the boot services, runtime services and configuration table definitions. So drop the unused ones.
--- arch/x86/boot/compressed/eboot.h | 12 - drivers/firmware/efi/libstub/random.c | 10 - include/linux/efi.h | 233 +------------------- 3 files changed, 1 insertion(+), 254 deletions(-)
arch/x86/boot/compressed/eboot.h +0 -12
@@ -12,18 +12,6 @@#define DESC_TYPE_CODE_DATA (1 << 0) -typedef struct { -u32 get_mode; -u32 set_mode; -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 union { struct { void *get_mode;
drivers/firmware/efi/libstub/random.c +0 -10
@@ -11,16 +11,6 @@typedef union efi_rng_protocol efi_rng_protocol_t ; -typedef struct { -u32 get_info; -u32 get_rng; -}efi_rng_protocol_32_t ; - -typedef struct { -u64 get_info; -u64 get_rng; -}efi_rng_protocol_64_t ; - union efi_rng_protocol { struct { efi_status_t (*get_info)(efi_rng_protocol_t *,
include/linux/efi.h +1 -232
299 lines not on this page · raw message
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 8/21 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 | 9 ++++++--- drivers/firmware/efi/libstub/efi-stub-helper.c | 5 +++-- drivers/firmware/efi/libstub/tpm.c | 4 ++-- include/linux/efi.h | 6 +++++- 5 files changed, 22 insertions(+), 12 deletions(-)
arch/x86/boot/compressed/eboot.c +6 -4
@@ -63,7 +63,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;
@@ -188,9 +189,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 ;
@@ -205,7 +206,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 +6 -3
@@ -12,9 +12,12 @@#define DESC_TYPE_CODE_DATA (1 << 0) -typedef union { +typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t ; + +union efi_uga_draw_protocol {struct { - void *get_mode; +efi_status_t (*get_mode)(efi_uga_draw_protocol_t *, +u32 *,u32 *,u32 *,u32 *);void *set_mode;void *blt; };
@@ -23,6 +26,6 @@ typedef union {u32 set_mode; u32 blt; } mixed_mode; -} efi_uga_draw_protocol_t; +};#endif /* BOOT_COMPRESSED_EBOOT_H */
drivers/firmware/efi/libstub/efi-stub-helper.c +3 -2
@@ -418,12 +418,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
@@ -69,11 +69,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
@@ -388,7 +388,11 @@ union efi_pci_io_protocol {void *allocate_buffer;void *free_buffer;void *flush; -void *get_location; +efi_status_t (*get_location)(efi_pci_io_protocol_t *, +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 v2 9/21 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 | 10 +- include/linux/efi.h | 156 +++++++++++--------- 4 files changed, 96 insertions(+), 75 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
@@ -16,8 +16,8 @@ typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;union efi_uga_draw_protocol {struct { -efi_status_t (*get_mode)(efi_uga_draw_protocol_t *, -u32 *,u32 *,u32 *,u32 *); + efi_status_t (__efiapi *get_mode)(efi_uga_draw_protocol_t *, + u32*, u32*, u32*, u32*);void *set_mode;void *blt; };
drivers/firmware/efi/libstub/random.c +6 -4
@@ -13,10 +13,12 @@ typedef union efi_rng_protocol efi_rng_protocol_t;union efi_rng_protocol {struct { -efi_status_t (*get_info)(efi_rng_protocol_t *, -unsigned long *,efi_guid_t *); -efi_status_t (*get_rng)(efi_rng_protocol_t *, -efi_guid_t *,unsigned long ,u8 *out); + efi_status_t (__efiapi *get_info)(efi_rng_protocol_t *, + unsigned long *, + efi_guid_t *); + efi_status_t (__efiapi *get_rng)(efi_rng_protocol_t *, + efi_guid_t *, unsigned long, + u8 *out); };struct {u32 get_info;
include/linux/efi.h +87 -69
247 lines not on this page · raw message
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 10/21 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 | 30 +++---- arch/x86/platform/efi/efi_64.c | 2 - 7 files changed, 17 insertions(+), 127 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 +16 -14
@@ -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;
@@ -235,30 +235,32 @@ static inline bool efi_is_native(void) (unsigned long)(attr), (attr))#define efi_table_attr (table, attr, instance) ({ \ - __typeof__(((table##_t *)0)->attr) __ret; \ + __typeof__(instance->attr) __ret; \ if (efi_is_native()) { \ - __ret = ((table##_t *)(unsigned long)instance)->attr; \ + __ret = instance->attr; \ } else { \ - __ret = (__typeof__(__ret))efi_mixed_mode_cast( \ - ((table##_t *)(unsigned long)instance)->mixed_mode.attr);\ + __ret = (__typeof__(__ret)) \ + efi_mixed_mode_cast(instance->mixed_mode.attr); \ } \ __ret; \ })#define efi_call_proto (protocol, f, instance, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(protocol, f, instance), \ - instance, ##__VA_ARGS__) + (efi_is_native() \ + ? instance->f(instance, ##__VA_ARGS__) \ + : efi64_thunk(instance->mixed_mode.f, instance, ##__VA_ARGS__))#define efi_call_early (f, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(efi_boot_services, f, \ - __efi_early()->boot_services), __VA_ARGS__) + (efi_is_native() \ + ? __efi_early()->boot_services->f(__VA_ARGS__) \ + : efi64_thunk(__efi_early()->boot_services->mixed_mode.f,\ + __VA_ARGS__))#define efi_call_runtime (f, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(efi_runtime_services, f, \ - __efi_early()->runtime_services), __VA_ARGS__) + (efi_is_native() \ + ? __efi_early()->runtime_services->f(__VA_ARGS__) \ + : efi64_thunk(__efi_early()->runtime_services->mixed_mode.f,\ + __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 v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Hi Ard,
Quoted 9 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>
I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few pr_efi_err calls and see if those still do something.
I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id a37d90a2c570a25926fd1645482cb9f3c1d042a0 and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Regards,
Hans
Quoted 283 lines
--- 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 | 30 +++---- arch/x86/platform/efi/efi_64.c | 2 - 7 files changed, 17 insertions(+), 127 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).oarch/x86/boot/compressed/efi_stub_32.S deleted +0
-87@@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * EFI call stub for IA32. - * - * This stub allows us to make EFI calls in physical mode with interrupts - * turned off. Note that this implementation is different from the one in - * arch/x86/platform/efi/efi_stub_32.S because we're _already_ in physical - * mode at this point. - */ - -#include <linux/linkage.h> -#include <asm/page_types.h> - -/* - * efi_call_phys(void *, ...) is a function with variable parameters. - * All the callers of this function assure that all the parameters are 4-bytes. - */ - -/* - * In gcc calling convention, EBX, ESP, EBP, ESI and EDI are all callee save. - * So we'd better save all of them at the beginning of this function and restore - * at the end no matter how many we use, because we can not assure EFI runtime - * service functions will comply with gcc calling convention, too. - */ - -.text -SYM_FUNC_START(efi_call_phys) - /* - * 0. The function can only be called in Linux kernel. So CS has been - * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found - * the values of these registers are the same. And, the corresponding - * GDT entries are identical. So I will do nothing about segment reg - * and GDT, but change GDT base register in prelog and epilog. - */ - - /* - * 1. Because we haven't been relocated by this point we need to - * use relative addressing. - */ - call 1f -1: popl %edx - subl $1b, %edx - - /* - * 2. Now on the top of stack is the return - * address in the caller of efi_call_phys(), then parameter 1, - * parameter 2, ..., param n. To make things easy, we save the return - * address of efi_call_phys in a global variable. - */ - popl %ecx - movl %ecx, saved_return_addr(%edx) - /* get the function pointer into ECX*/ - popl %ecx - movl %ecx, efi_rt_function_ptr(%edx) - - /* - * 3. Call the physical function. - */ - call *%ecx - - /* - * 4. Balance the stack. And because EAX contain the return value, - * we'd better not clobber it. We need to calculate our address - * again because %ecx and %edx are not preserved across EFI function - * calls. - */ - call 1f -1: popl %edx - subl $1b, %edx - - movl efi_rt_function_ptr(%edx), %ecx - pushl %ecx - - /* - * 10. Push the saved return address onto the stack and return. - */ - movl saved_return_addr(%edx), %ecx - pushl %ecx - ret -SYM_FUNC_END(efi_call_phys) -.previous - -.data -saved_return_addr: - .long 0 -efi_rt_function_ptr: - .long 0arch/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 #endifarch/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 +16
-14@@ -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;@@ -235,30 +235,32 @@ static inline bool efi_is_native(void) (unsigned long)(attr), (attr))#define efi_table_attr (table, attr, instance) ({ \ - __typeof__(((table##_t *)0)->attr) __ret; \ + __typeof__(instance->attr) __ret; \ if (efi_is_native()) { \ - __ret = ((table##_t *)(unsigned long)instance)->attr; \ + __ret = instance->attr; \ } else { \ - __ret = (__typeof__(__ret))efi_mixed_mode_cast( \ - ((table##_t *)(unsigned long)instance)->mixed_mode.attr);\ + __ret = (__typeof__(__ret)) \ + efi_mixed_mode_cast(instance->mixed_mode.attr); \ } \ __ret; \ })#define efi_call_proto (protocol, f, instance, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(protocol, f, instance), \ - instance, ##__VA_ARGS__) + (efi_is_native() \ + ? instance->f(instance, ##__VA_ARGS__) \ + : efi64_thunk(instance->mixed_mode.f, instance, ##__VA_ARGS__))#define efi_call_early (f, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(efi_boot_services, f, \ - __efi_early()->boot_services), __VA_ARGS__) + (efi_is_native() \ + ? __efi_early()->boot_services->f(__VA_ARGS__) \ + : efi64_thunk(__efi_early()->boot_services->mixed_mode.f,\ + __VA_ARGS__))#define efi_call_runtime (f, ...) \ - __efi_early()->call((unsigned long) \ - efi_table_attr(efi_runtime_services, f, \ - __efi_early()->runtime_services), __VA_ARGS__) + (efi_is_native() \ + ? __efi_early()->runtime_services->f(__VA_ARGS__) \ + : efi64_thunk(__efi_early()->runtime_services->mixed_mode.f,\ + __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) \
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 9 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.
Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call efi_main' in the .S stub code for x86_64 makes a difference?
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 46 lines · Ard Biesheuvel
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 9 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
Quoted 7 lines
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call
efi_main' in the .S stub code forx86_64makes a difference?
... or in case that does not help, I have updated my -v3 branch to split the removal of the thunking sequence for x86_64 in several discrete steps.
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
In reply to Ard BiesheuvelQuoted 49 lines · Ard Biesheuvel
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 10 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
Quoted 7 lines
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call
efi_main' in the .S stub code forx86_64makes a difference?
Hmm. Most of the kernel is compiled with the stack alignment set to 8, and there a lot of asm that makes no effort to preserve alignment beyond 8 bytes. So if EFI calls need 16 byte alignment, you may need to do something special.
On new enough gcc (the versions that actually support the flags to set the alignment to 8), maybe you can use function attributes, or maybe you can stick a 16-byte-aligned local variable in functions that call EFI functions? The latter would be rather fragile.
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 54 lines · Andy Lutomirski
Quoted 54 lines · Ard Biesheuvel
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 10 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
Quoted 7 lines
Quoted 3 lines
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call
efi_main' in the .S stub code forx86_64makes a difference?Hmm. Most of the kernel is compiled with the stack alignment set to 8, and there a lot of asm that makes no effort to preserve alignment beyond 8 bytes. So if EFI calls need 16 byte alignment, you may need to do something special.
On new enough gcc (the versions that actually support the flags to set the alignment to 8), maybe you can use function attributes, or maybe you can stick a 16-byte-aligned local variable in functions that call EFI functions? The latter would be rather fragile.
This patch replaces open coded SysV to MS calling convention translation to GCC generated code (using __attribute__((ms_abi)) which we have been using for a long time in EDK2), because the former relies on a wrapper function
efi_call(fn, ...)
which is type unsafe and relies on a lot of nasty casting, especially combined with the mixed mode support. efi_call() is implemented as below, and as Hans reports, omitting this sequence causes a boot regression on one of the platforms he has tested this on.
So the question is which of the pieces below this UEFI implementation is actually relying on, and the stack pointer alignment is my first guess, but it could be any of the other things as well. Once we identify what it is we are missing, I can simply stick it back in, but without reverting to using the efi_call() thunk.
Note that the decompressor/stub are built with the default stack alignment of 16 afaict, but if GRUB enters the decompressor with a misaligned stack, we probably wouldn't notice until we hit something like a movaps, right?
Thanks,
Ard.
#define SAVE_XMM \
mov %rsp, %rax; \
subq $0x70, %rsp; \
and $~0xf, %rsp; \
mov %rax, (%rsp); \
mov %cr0, %rax; \
clts; \
mov %rax, 0x8(%rsp); \
movaps %xmm0, 0x60(%rsp); \
movaps %xmm1, 0x50(%rsp); \
movaps %xmm2, 0x40(%rsp); \
movaps %xmm3, 0x30(%rsp); \
movaps %xmm4, 0x20(%rsp); \
movaps %xmm5, 0x10(%rsp)#define RESTORE_XMM \
movaps 0x60(%rsp), %xmm0; \
movaps 0x50(%rsp), %xmm1; \
movaps 0x40(%rsp), %xmm2; \
movaps 0x30(%rsp), %xmm3; \
movaps 0x20(%rsp), %xmm4; \
movaps 0x10(%rsp), %xmm5; \
mov 0x8(%rsp), %rsi; \
mov %rsi, %cr0; \
mov (%rsp), %rspSYM_FUNC_START(efi_call)
pushq %rbp
movq %rsp, %rbp
SAVE_XMM
mov 16(%rbp), %rax
subq $48, %rsp
mov %r9, 32(%rsp)
mov %rax, 40(%rsp)
mov %r8, %r9
mov %rcx, %r8
mov %rsi, %rcx
call *%rdi
addq $48, %rsp
RESTORE_XMM
popq %rbp
retSYM_FUNC_END(efi_call)
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 24 lines · Ard Biesheuvel
Quoted 4 lines · Andy Lutomirski
Hmm. Most of the kernel is compiled with the stack alignment set to 8, and there a lot of asm that makes no effort to preserve alignment beyond 8 bytes. So if EFI calls need 16 byte alignment, you may need to do something special.
On new enough gcc (the versions that actually support the flags to set the alignment to 8), maybe you can use function attributes, or maybe you can stick a 16-byte-aligned local variable in functions that call EFI functions? The latter would be rather fragile.
This patch replaces open coded SysV to MS calling convention translation to GCC generated code (using __attribute__((ms_abi)) which we have been using for a long time in EDK2), because the former relies on a wrapper function
efi_call(fn, ...)which is type unsafe and relies on a lot of nasty casting, especially combined with the mixed mode support.
efi_call()is implemented as below, and as Hans reports, omitting this sequence causes a boot regression on one of the platforms he has tested this on.So the question is which of the pieces below this UEFI implementation is actually relying on, and the stack pointer alignment is my first guess, but it could be any of the other things as well. Once we identify what it is we are missing, I can simply stick it back in, but without reverting to using the
efi_call()thunk.
Quoted 8 lines
Note that the decompressor/stub are built with the default stack alignment of 16 afaict, but if GRUB enters the decompressor with a misaligned stack, we probably wouldn't notice until we hit something like a movaps, right?
Thanks,
Ard.
Won't the entry code misalign the stack when efi_main is called, assuming the stack was properly aligned at efi_stub_entry? There needs to be a sub $8, %rsp in there, no?
arch/x86/boot/compressed/head_64.S:
#ifdef CONFIG_EFI_STUB
.org 0x390SYM_FUNC_START(efi64_stub_entry)SYM_FUNC_START_ALIAS(efi_stub_entry)
movq $1, %rcxhandover_entry:
call efi_main <--- this will enter efi_main with a misaligned stack?
movq %rax,%rsi
movl BP_code32_start(%esi), %eax
leaq startup_64(%rax), %rax
jmp *%raxSYM_FUNC_END(efi64_stub_entry)SYM_FUNC_END_ALIAS(efi_stub_entry)
#endif
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 47 lines · Arvind Sankar
Quoted 24 lines · Ard Biesheuvel
Quoted 4 lines · Andy Lutomirski
Hmm. Most of the kernel is compiled with the stack alignment set to 8, and there a lot of asm that makes no effort to preserve alignment beyond 8 bytes. So if EFI calls need 16 byte alignment, you may need to do something special.
On new enough gcc (the versions that actually support the flags to set the alignment to 8), maybe you can use function attributes, or maybe you can stick a 16-byte-aligned local variable in functions that call EFI functions? The latter would be rather fragile.
This patch replaces open coded SysV to MS calling convention translation to GCC generated code (using __attribute__((ms_abi)) which we have been using for a long time in EDK2), because the former relies on a wrapper function
efi_call(fn, ...)which is type unsafe and relies on a lot of nasty casting, especially combined with the mixed mode support.
efi_call()is implemented as below, and as Hans reports, omitting this sequence causes a boot regression on one of the platforms he has tested this on.So the question is which of the pieces below this UEFI implementation is actually relying on, and the stack pointer alignment is my first guess, but it could be any of the other things as well. Once we identify what it is we are missing, I can simply stick it back in, but without reverting to using the
efi_call()thunk.Quoted 8 lines
Note that the decompressor/stub are built with the default stack alignment of 16 afaict, but if GRUB enters the decompressor with a misaligned stack, we probably wouldn't notice until we hit something like a movaps, right?
Thanks,
Ard.Won't the entry code misalign the stack when
efi_mainis called, assuming the stack was properly aligned atefi_stub_entry? There needs to be a sub $8, %rsp in there, no?
arch/x86/boot/compressed/head_64.S:#ifdef CONFIG_EFI_STUB .org 0x390
SYM_FUNC_START(efi64_stub_entry)SYM_FUNC_START_ALIAS(efi_stub_entry)
movq $1, %rcxhandover_entry:
Quoted 9 lines
call efi_main <--- this will enter efi_main with a misaligned stack? movq %rax,%rsi movl BP_code32_start(%esi), %eax leaq startup_64(%rax), %rax jmp *%rax
SYM_FUNC_END(efi64_stub_entry)SYM_FUNC_END_ALIAS(efi_stub_entry)
#endif
Indeed, well spotted. Note that the above is the version from the top of that branch, but the version that Hans tested isn't any different.
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
In reply to Ard BiesheuvelHi Ard,
Quoted 45 lines · Ard Biesheuvel
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 9 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
Quoted 7 lines
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call
efi_main' in the .S stub code forx86_64makes a difference?
Ok, so I made this change on top of a37d90a2c570a25926fd1645482cb9f3c1d042a0 (the last "efi/libstub/x86: avoid thunking for native firmware calls" version I tried before reporting this problem) :
arch/x86/boot/compressed/head_64.S +1 -0
@@ -464,6 +464,7 @@ SYM_FUNC_START(efi_pe_entry) handover_entry: movq efi_config(%rip), %rdi + and $~0xf, %rsp call efi_main movq %rax,%rsi cmpq $0,%rax
And that does the trick, the GPD pocket boots successfully with commit a37d90a2c570a25926fd1645482cb9f3c1d042a0 + the above change.
So it looks like your first hunch on how to fix this is correct :)
Regards,
Hans
Re: [PATCH v2 10/21] efi/libstub/x86: avoid thunking for native firmware calls
Quoted 72 lines · Hans de Goede
Hi Ard,
Quoted 45 lines · Ard Biesheuvel
Quoted 35 lines · Hans de Goede
Hi Ard,
Quoted 9 lines · Ard Biesheuvel
We 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.
Quoted 4 lines
So drop all the wrappers and indirection, and switch to either native calls, or direct calls into the thunk routine for mixed mode.
Signed-off-by Ard Biesheuvel <[email protected]>I'm afraid that this patch breaks the boot on one of my machines.
Specifically this patch breaks my GDP pocket machine. This is a Cherry Trail device with a 64 UEFI running a 64 bit kernel build.
As soon as I cherry pick this patch into my personal 5.5.0-rc2 based tree, the GPD pocket stops booting and it stop so early on that I get 0 debug output. I guess I could try adding a few
pr_efi_errcalls and see if those still do something.I noticed that you have made some changes to this patch, I've tried updating it to the version from your efistub-x86-cleanup-v3 branch, commit id
a37d90a2c570a25926fd1645482cb9f3c1d042a0and I have also cherry-picked the latest version of all preceding commits, unfortunately even with the new version, the GPD pocket still hangs at boot.Quoted 6 lines
Unfortunately the nature of this patch makes it hard to figure out the root cause of this issue...
I've also tried another Cherry Trail device with 64 bit UEFI and that does not suffer from this problem.
Thanks Hans.
Quoted 7 lines
There are a number of things that change in the way the calls are made, but the most obvious thing to check is whether the stack needs to be aligned, since that is no longer being done.
If you have time to experiment a bit more, could you check whether doing 'and $~0xf %rsp' before 'call
efi_main' in the .S stub code forx86_64makes a difference?Ok, so I made this change on top of
a37d90a2c570a25926fd1645482cb9f3c1d042a0(the last "efi/libstub/x86: avoid thunking for native firmware calls" version I tried before reporting this problem) :arch/x86/boot/compressed/head_64.S +1
-0@@ -464,6 +464,7 @@ SYM_FUNC_START(efi_pe_entry) handover_entry: movq efi_config(%rip), %rdi + and $~0xf, %rsp call efi_main movq %rax,%rsi cmpq $0,%rax
Quoted 5 lines
And that does the trick, the GPD pocket boots successfully with commit
a37d90a2c570a25926fd1645482cb9f3c1d042a0+ the above change.So it looks like your first hunch on how to fix this is correct :)
Excellent! Thanks for testing.
I'll fold this in.
Ard Biesheuvel
maintainerPATCH v2 11/21 efi/libstub: get rid of 'sys_table_arg' macro parameter
In reply to Ard BiesheuvelThe efi_call macros on ARM have a dependency on a variable 'sys_table_arg' existing in the scope of the macro instantiation. Since this variable always points to the same data structure, let's create a global getter for it and use that instead.
Note that the use of a global variable with external linkage is avoided, given the problems we had in the past with early processing of the GOT tables.
While at it, drop the redundant casts in the efi_table_attr and efi_call_proto macros.
--- arch/arm/include/asm/efi.h | 8 ++++---- arch/arm64/include/asm/efi.h | 8 ++++---- arch/x86/boot/compressed/eboot.c | 5 +++++ drivers/firmware/efi/libstub/arm-stub.c | 11 ++++++++++- drivers/firmware/efi/libstub/efistub.h | 2 ++ drivers/firmware/efi/libstub/gop.c | 2 ++ 6 files changed, 27 insertions(+), 9 deletions(-)
arch/arm/include/asm/efi.h +4 -4
@@ -50,15 +50,15 @@ 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_runtime (f, ...) sys_table_arg->runtime->f(__VA_ARGS__) +#define efi_call_early (f, ...) efi_system_table()->boottime->f(__VA_ARGS__) +#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__)#define efi_is_native () (true)#define efi_table_attr (table, attr, instance) \ - ((table##_t *)instance)->attr + instance->attr#define efi_call_proto (protocol, f, instance, ...) \ - ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) + instance->f(instance, ##__VA_ARGS__)struct screen_info *alloc_screen_info (efi_system_table_t *sys_table_arg);void free_screen_info (efi_system_table_t *sys_table,struct screen_info *si);
arch/arm64/include/asm/efi.h +4 -4
@@ -93,15 +93,15 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,return (image_addr & ~(SZ_1G -1UL )) + (1UL << (VA_BITS_MIN -1 )); } -#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_early (f, ...) efi_system_table()->boottime->f(__VA_ARGS__) +#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__)#define efi_is_native () (true)#define efi_table_attr (table, attr, instance) \ - ((table##_t *)instance)->attr + instance->attr#define efi_call_proto (protocol, f, instance, ...) \ - ((protocol##_t *)instance)->f(instance, ##__VA_ARGS__) + instance->f(instance, ##__VA_ARGS__) #define alloc_screen_info(x...) &screen_info
arch/x86/boot/compressed/eboot.c +5 -0
@@ -27,6 +27,11 @@ __pure const struct efi_config *__efi_early(void)return efi_early; } +__pure efi_system_table_t *efi_system_table (void ) +{ +return sys_table; +} +static void setup_boot_services (struct efi_config *c) { c->runtime_services =efi_table_attr (efi_system_table, runtime, sys_table);
drivers/firmware/efi/libstub/arm-stub.c +10 -1
@@ -37,6 +37,13 @@static u64 virtmap_base =EFI_RT_VIRTUAL_BASE ; +static efi_system_table_t *__section(.data) sys_table; + +__pure efi_system_table_t *efi_system_table (void ) +{ +return sys_table; +} +void efi_char16_printk (efi_system_table_t *sys_table_arg,efi_char16_t *str) {
@@ -110,7 +117,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,* for both archictectures, with the arch-specific code provided in the * handle_kernel_image() function. */ -unsigned long efi_entry (void *handle,efi_system_table_t *sys_table, +unsigned long efi_entry (void *handle,efi_system_table_t *sys_table_arg,unsigned long *image_addr) {efi_loaded_image_t *image;
@@ -131,6 +138,8 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,enum efi_secureboot_mode secure_boot;struct screen_info *si; + sys_table = sys_table_arg; +/* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE ) goto fail;
drivers/firmware/efi/libstub/efistub.h +2 -0
@@ -29,6 +29,8 @@ extern int __pure nokaslr(void);extern int __pure is_quiet (void );extern int __pure novamap (void ); +extern __pure efi_system_table_t *efi_system_table (void ); +#define pr_efi (sys_table, msg) do { \ if (!is_quiet()) efi_printk(sys_table, "EFI stub: "msg); \ } while (0)
drivers/firmware/efi/libstub/gop.c +2 -0
@@ -10,6 +10,8 @@#include <asm/efi.h> #include <asm/setup.h> +#include "efistub.h" +static void find_bits (unsigned long mask,u8 *pos,u8 *size) {u8 first, len;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 12/21 efi/libstub: unify the efi_char16_printk implementations
In reply to Ard BiesheuvelUse a single implementation for efi_char16_printk() across all architectures.
--- arch/x86/boot/compressed/eboot.c | 6 ------ drivers/firmware/efi/libstub/arm-stub.c | 9 --------- drivers/firmware/efi/libstub/efi-stub-helper.c | 9 +++++++++ 3 files changed, 9 insertions(+), 15 deletions(-)
arch/x86/boot/compressed/eboot.c +0 -6
@@ -39,12 +39,6 @@ static void setup_boot_services(struct efi_config *c) c->text_output =efi_table_attr (efi_system_table, con_out, sys_table); } -void efi_char16_printk (efi_system_table_t *table,efi_char16_t *str) -{ -efi_call_proto (efi_simple_text_output_protocol, output_string, - efi_early->text_output, str); -} -static efi_status_t preserve_pci_rom_image (efi_pci_io_protocol_t *pci,struct pci_setup_rom **__rom) {
drivers/firmware/efi/libstub/arm-stub.c +0 -9
@@ -44,15 +44,6 @@ __pure efi_system_table_t *efi_system_table(void)return sys_table; } -void efi_char16_printk (efi_system_table_t *sys_table_arg, -efi_char16_t *str) -{ -efi_simple_text_output_protocol_t *out; - - out = (efi_simple_text_output_protocol_t *)sys_table_arg->con_out; - out->output_string (out, str); -} -static struct screen_info *setup_graphics (efi_system_table_t *sys_table_arg) {efi_guid_t gop_proto =EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID ;
drivers/firmware/efi/libstub/efi-stub-helper.c +9 -0
@@ -975,3 +975,12 @@ void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) }return NULL ; } + +void efi_char16_printk (efi_system_table_t *table,efi_char16_t *str) +{ +efi_call_proto (efi_simple_text_output_protocol, + output_string, +efi_table_attr (efi_system_table, con_out, +efi_system_table ()), + str); +}
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 13/21 efi/libstub/x86: drop __efi_early() export of efi_config struct
In reply to Ard BiesheuvelThe various pointers we stash in the efi_config struct which we retrieve using __efi_early() are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the __efi_early() related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.
--- arch/x86/boot/compressed/eboot.c | 36 ++++++++------------ arch/x86/boot/compressed/head_32.S | 2 +- arch/x86/boot/compressed/head_64.S | 4 +-- arch/x86/include/asm/efi.h | 23 +++++-------- 4 files changed, 26 insertions(+), 39 deletions(-)
arch/x86/boot/compressed/eboot.c +15 -21
@@ -20,11 +20,17 @@static efi_system_table_t *sys_table; -static struct efi_config *efi_early; +struct efi_config { +u64 image_handle; +u64 table; +bool is64; +} __packed; -__pure const struct efi_config *__efi_early (void ) +static bool is64; + +__pure bool __efi_early_is64 (void ) { -return efi_early; +return is64; }__pure efi_system_table_t *efi_system_table (void )
@@ -32,13 +38,6 @@ __pure efi_system_table_t *efi_system_table(void)return sys_table; } -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); -} -static efi_status_t preserve_pci_rom_image (efi_pci_io_protocol_t *pci,struct pci_setup_rom **__rom) {
@@ -382,16 +381,14 @@ struct boot_params *make_boot_params(struct efi_config *c)unsigned long ramdisk_addr;unsigned long ramdisk_size; - efi_early = c; - sys_table = (efi_system_table_t *)(unsigned long )efi_early->table; - handle = (void *)(unsigned long )efi_early->image_handle; + sys_table = (efi_system_table_t *)(unsigned long )c->table; + handle = (void *)(unsigned long )c->image_handle; + is64 = c->is64;/* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE )return NULL ; -setup_boot_services (efi_early); - status =efi_call_early (handle_protocol, handle, &proto, (void *)&image);if (status !=EFI_SUCCESS ) {
@@ -738,10 +735,9 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)efi_system_table_t *_table;unsigned long cmdline_paddr; - efi_early = c; - - _table = (efi_system_table_t *)(unsigned long )efi_early->table; - handle = (void *)(unsigned long )efi_early->image_handle; + _table = (efi_system_table_t *)(unsigned long )c->table; + handle = (void *)(unsigned long )c->image_handle; + is64 = c->is64; sys_table = _table;
@@ -749,8 +745,6 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE ) goto fail; -setup_boot_services (efi_early); -/* * make_boot_params() may have been called before efi_main(), in which * case this is the second time we parse the cmdline. This is ok,
arch/x86/boot/compressed/head_32.S +1 -1
@@ -261,7 +261,7 @@ SYM_FUNC_END(.Lrelocated) #ifdef CONFIG_EFI_STUB .data efi32_config: - .fill 7,4,0 + .fill 4,4,0 .byte 0 #endif
arch/x86/boot/compressed/head_64.S +2 -2
@@ -672,13 +672,13 @@ SYM_DATA_LOCAL(efi_config, .quad 0) #ifdef CONFIG_EFI_MIXED SYM_DATA_START(efi32_config) - .fill 5,8,0 + .fill 2,8,0 .byte 0 SYM_DATA_END(efi32_config) #endif SYM_DATA_START(efi64_config) - .fill 5,8,0 + .fill 2,8,0 .byte 1 SYM_DATA_END(efi64_config) #endif /* CONFIG_EFI_STUB */
arch/x86/include/asm/efi.h +8 -15
@@ -200,16 +200,7 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(/* arch specific definitions used by the stub code */ -struct efi_config { -u64 image_handle; -u64 table; -efi_runtime_services_t *runtime_services; -efi_boot_services_t *boot_services; -efi_simple_text_output_protocol_t *text_output; -bool is64; -} __packed; - -__pure const struct efi_config *__efi_early (void ); +__pure bool __efi_early_is64 (void );static inline bool efi_is_64bit (void ) {
@@ -219,7 +210,7 @@ static inline bool efi_is_64bit(void)if (!IS_ENABLED (CONFIG_EFI_MIXED ))return true; -return __efi_early ()->is64; +return __efi_early_is64 (); }static inline bool efi_is_native (void )
@@ -252,14 +243,16 @@ static inline bool efi_is_native(void)#define efi_call_early (f, ...) \ (efi_is_native() \ - ? __efi_early()->boot_services->f(__VA_ARGS__) \ - : efi64_thunk(__efi_early()->boot_services->mixed_mode.f,\ + ? efi_system_table()->boottime->f(__VA_ARGS__) \ + : efi64_thunk(efi_table_attr(efi_boot_services, \ + boottime, efi_system_table())->mixed_mode.f, \ __VA_ARGS__))#define efi_call_runtime (f, ...) \ (efi_is_native() \ - ? __efi_early()->runtime_services->f(__VA_ARGS__) \ - : efi64_thunk(__efi_early()->runtime_services->mixed_mode.f,\ + ? efi_system_table()->runtime->f(__VA_ARGS__) \ + : efi64_thunk(efi_table_attr(efi_runtime_services, \ + runtime, efi_system_table())->mixed_mode.f, \ __VA_ARGS__))extern bool efi_reboot_required (void );
Signature · 1 line
2.17.1
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Hi Ard,
Quoted 8 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>
I synced my personal tree yesterday to 5.5-rc3 + the most recent version (as of yesterday afternoon) of your efistub-x86-cleanup-v3 branch on top.
This has been working fine on a bunch of devices, but it fails on a Teclast X89 Bay Trail (mixed mode) device. When reverting all the commits from your efistub-x86-cleanup-v3 branch one by one, things start working again after reverting this one.
Regards,
Hans
Quoted 175 lines
--- arch/x86/boot/compressed/eboot.c | 36 ++++++++------------ arch/x86/boot/compressed/head_32.S | 2 +- arch/x86/boot/compressed/head_64.S | 4 +-- arch/x86/include/asm/efi.h | 23 +++++-------- 4 files changed, 26 insertions(+), 39 deletions(-)arch/x86/boot/compressed/eboot.c +15
-21@@ -20,11 +20,17 @@static efi_system_table_t *sys_table; -static struct efi_config *efi_early; +struct efi_config { +u64 image_handle; +u64 table; +bool is64; +} __packed; -__pure const struct efi_config *__efi_early (void ) +static bool is64; + +__pure bool __efi_early_is64 (void ) { -return efi_early; +return is64; }__pure efi_system_table_t *efi_system_table (void )@@ -32,13 +38,6 @@ __pure efi_system_table_t *efi_system_table(void)return sys_table; } -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); -} -static efi_status_t preserve_pci_rom_image (efi_pci_io_protocol_t *pci,struct pci_setup_rom **__rom) {@@ -382,16 +381,14 @@ struct boot_params *make_boot_params(struct efi_config *c)unsigned long ramdisk_addr;unsigned long ramdisk_size; - efi_early = c; - sys_table = (efi_system_table_t *)(unsigned long )efi_early->table; - handle = (void *)(unsigned long )efi_early->image_handle; + sys_table = (efi_system_table_t *)(unsigned long )c->table; + handle = (void *)(unsigned long )c->image_handle; + is64 = c->is64;/* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE )return NULL ; -setup_boot_services (efi_early); - status =efi_call_early (handle_protocol, handle, &proto, (void *)&image);if (status !=EFI_SUCCESS ) {@@ -738,10 +735,9 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)efi_system_table_t *_table;unsigned long cmdline_paddr; - efi_early = c; - - _table = (efi_system_table_t *)(unsigned long )efi_early->table; - handle = (void *)(unsigned long )efi_early->image_handle; + _table = (efi_system_table_t *)(unsigned long )c->table; + handle = (void *)(unsigned long )c->image_handle; + is64 = c->is64; sys_table = _table;@@ -749,8 +745,6 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)if (sys_table->hdr.signature !=EFI_SYSTEM_TABLE_SIGNATURE ) goto fail; -setup_boot_services (efi_early); -/* * make_boot_params() may have been called before efi_main(), in which * case this is the second time we parse the cmdline. This is ok, arch/x86/boot/compressed/head_32.S +1
-1@@ -261,7 +261,7 @@ SYM_FUNC_END(.Lrelocated) #ifdef CONFIG_EFI_STUB .data efi32_config: - .fill 7,4,0 + .fill 4,4,0 .byte 0 #endifarch/x86/boot/compressed/head_64.S +2
-2@@ -672,13 +672,13 @@ SYM_DATA_LOCAL(efi_config, .quad 0) #ifdef CONFIG_EFI_MIXED SYM_DATA_START(efi32_config) - .fill 5,8,0 + .fill 2,8,0 .byte 0 SYM_DATA_END(efi32_config) #endif SYM_DATA_START(efi64_config) - .fill 5,8,0 + .fill 2,8,0 .byte 1 SYM_DATA_END(efi64_config) #endif /* CONFIG_EFI_STUB */arch/x86/include/asm/efi.h +8
-15@@ -200,16 +200,7 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(/* arch specific definitions used by the stub code */ -struct efi_config { -u64 image_handle; -u64 table; -efi_runtime_services_t *runtime_services; -efi_boot_services_t *boot_services; -efi_simple_text_output_protocol_t *text_output; -bool is64; -} __packed; - -__pure const struct efi_config *__efi_early (void ); +__pure bool __efi_early_is64 (void );static inline bool efi_is_64bit (void ) {@@ -219,7 +210,7 @@ static inline bool efi_is_64bit(void)if (!IS_ENABLED (CONFIG_EFI_MIXED ))return true; -return __efi_early ()->is64; +return __efi_early_is64 (); }static inline bool efi_is_native (void )@@ -252,14 +243,16 @@ static inline bool efi_is_native(void)#define efi_call_early (f, ...) \ (efi_is_native() \ - ? __efi_early()->boot_services->f(__VA_ARGS__) \ - : efi64_thunk(__efi_early()->boot_services->mixed_mode.f,\ + ? efi_system_table()->boottime->f(__VA_ARGS__) \ + : efi64_thunk(efi_table_attr(efi_boot_services, \ + boottime, efi_system_table())->mixed_mode.f, \ __VA_ARGS__))#define efi_call_runtime (f, ...) \ (efi_is_native() \ - ? __efi_early()->runtime_services->f(__VA_ARGS__) \ - : efi64_thunk(__efi_early()->runtime_services->mixed_mode.f,\ + ? efi_system_table()->runtime->f(__VA_ARGS__) \ + : efi64_thunk(efi_table_attr(efi_runtime_services, \ + runtime, efi_system_table())->mixed_mode.f, \ __VA_ARGS__))extern bool efi_reboot_required (void );
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 13 lines · Hans de Goede
Hi Ard,
Quoted 8 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>
Quoted 9 lines
I synced my personal tree yesterday to 5.5-rc3 + the most recent version (as of yesterday afternoon) of your efistub-x86-cleanup-v3 branch on top.
This has been working fine on a bunch of devices, but it fails on a Teclast X89 Bay Trail (mixed mode) device. When reverting all the commits from your efistub-x86-cleanup-v3 branch one by one, things start working again after reverting this one.
Oops again. And thanks again for taking the time to test this stuff.
Could you please try the branch below and check whether it fixes it?
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-core-mm-fix
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Hi,
Quoted 24 lines · Ard Biesheuvel
Quoted 13 lines · Hans de Goede
Hi Ard,
Quoted 8 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>Quoted 9 lines
I synced my personal tree yesterday to 5.5-rc3 + the most recent version (as of yesterday afternoon) of your efistub-x86-cleanup-v3 branch on top.
This has been working fine on a bunch of devices, but it fails on a Teclast X89 Bay Trail (mixed mode) device. When reverting all the commits from your efistub-x86-cleanup-v3 branch one by one, things start working again after reverting this one.
Quoted 5 lines
Oops again. And thanks again for taking the time to test this stuff.
Could you please try the branch below and check whether it fixes it?
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-core-mm-fix
This seems to fix the issue, the Teclast X89 boots again and I've also tested this on 2 other devices (one mixed mode Bay Trail one 64 bit Cherry Trail device).
If I want to also test them, how do the 2 new series you've just posted come into the mix here? :
"[PATCH 0/3] efi/x86: clean up and simplify runtime call wrappers" "[PATCH 0/3] efi/x86: righten memory protections at runtime"
Regards,
Hans
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 30 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
Quoted 13 lines · Hans de Goede
Hi Ard,
Quoted 8 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>Quoted 9 lines
I synced my personal tree yesterday to 5.5-rc3 + the most recent version (as of yesterday afternoon) of your efistub-x86-cleanup-v3 branch on top.
This has been working fine on a bunch of devices, but it fails on a Teclast X89 Bay Trail (mixed mode) device. When reverting all the commits from your efistub-x86-cleanup-v3 branch one by one, things start working again after reverting this one.
Oops again. And thanks again for taking the time to test this stuff.
Quoted 8 lines
Quoted 3 lines
Could you please try the branch below and check whether it fixes it?
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-core-mm-fix
This seems to fix the issue, the Teclast X89 boots again and I've also tested this on 2 other devices (one mixed mode Bay Trail one 64 bit Cherry Trail device).
Great, thanks.
Quoted 6 lines
If I want to also test them, how do the 2 new series you've just posted come into the mix here? :
"[PATCH 0/3] efi/x86: clean up and simplify runtime call wrappers" "[PATCH 0/3] efi/x86: righten memory protections at runtime"
I have accumulated a couple of more fixes in addition, and a patch that I haven't sent out yet.
Easiest to grab them from
https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/log/?h=next
Signature · 1 line
Ard.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
In reply to Ard BiesheuvelQuoted 30 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/x86/boot/compressed/eboot.c | 36 ++++++++------------ arch/x86/boot/compressed/head_32.S | 2 +- arch/x86/boot/compressed/head_64.S | 4 +-- arch/x86/include/asm/efi.h | 23 +++++-------- 4 files changed, 26 insertions(+), 39 deletions(-)arch/x86/boot/compressed/eboot.c +5
-1@@ -20,11 +20,17 @@static efi_system_table_t *sys_table; -static struct efi_config *efi_early; +struct efi_config { +u64 image_handle; +u64 table; +bool is64; +} __packed;
arch/x86/boot/compressed/eboot.c line 36
Quoted 10 lines
arch/x86/boot/compressed/eboot.c +4
-2-__pure const struct efi_config *__efi_early (void ) +static bool is64; + +__pure bool __efi_early_is64 (void ) { -return efi_early; +return is64; }__pure efi_system_table_t *efi_system_table (void )
This predates your series, but looking at the generated code I noticed that pure isn't enough to let gcc optimize out repeated calls to is64 and system_table. Declaring them as __attribute_const__ would allow optimization. They don't quite meet gcc's requirements for that as they access global non-const variables, but it seems like it ought to be safe, especially if we stop using the functions within eboot.c itself?
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 41 lines · Arvind Sankar
Quoted 39 lines · Ard Biesheuvel
The various pointers we stash in the
efi_configstruct which we retrieve using__efi_early()are simply copies of the ones in the EFI system table, which we have started accessing directly in the previous patch. So drop all the__efi_early()related plumbing, except for the access to a boolean which tells us whether the firmware is 64-bit or not.Signed-off-by Ard Biesheuvel <[email protected]>--- arch/x86/boot/compressed/eboot.c | 36 ++++++++------------ arch/x86/boot/compressed/head_32.S | 2 +- arch/x86/boot/compressed/head_64.S | 4 +-- arch/x86/include/asm/efi.h | 23 +++++-------- 4 files changed, 26 insertions(+), 39 deletions(-)arch/x86/boot/compressed/eboot.c +9
-3@@ -20,11 +20,17 @@static efi_system_table_t *sys_table; -static struct efi_config *efi_early; +struct efi_config { +u64 image_handle; +u64 table; +bool is64; +} __packed; -__pure const struct efi_config *__efi_early (void ) +static bool is64; + +__pure bool __efi_early_is64 (void ) { -return efi_early; +return is64; }
Quoted 8 lines
arch/x86/boot/compressed/eboot.c line 36
Quoted 1 line
arch/x86/boot/compressed/eboot.c +0
-0__pure efi_system_table_t *efi_system_table (void )This predates your series, but looking at the generated code I noticed that pure isn't enough to let gcc optimize out repeated calls to is64 and
system_table. Declaring them as__attribute_const__would allow optimization. They don't quite meet gcc's requirements for that as they access global non-const variables, but it seems like it ought to be safe, especially if we stop using the functions withineboot.citself?
The GCC documentation mentions that it does not make sense for a function annotated as const not to take any arguments, so I'd rather avoid it here.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 3 lines · Ard Biesheuvel
The GCC documentation mentions that it does not make sense for a function annotated as const not to take any arguments, so I'd rather avoid it here.
Where does it say that? I only see it saying it doesn't make sense for it to return void.
Currently if we call 5 EFI services in the same function, it has to re-evaluate systemtable and is64 for each call, which seems wasteful, though of course this is not exactly performance-critical code.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 9 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
The GCC documentation mentions that it does not make sense for a function annotated as const not to take any arguments, so I'd rather avoid it here.
Where does it say that? I only see it saying it doesn't make sense for it to return void.
You're right. I looked into this in the past, and I misremembered, and paraphrased it incorrectly.
The documentation does mention that const functions are not permitted to read global memory.
Quoted 3 lines
Currently if we call 5 EFI services in the same function, it has to re-evaluate systemtable and is64 for each call, which seems wasteful, though of course this is not exactly performance-critical code.
The alternative would be to use globals with external linkage in a way that is guaranteed not to rely on GOT entries, since we'll end up with absolute addresses that need to be fixed up first. This has caused breakage in the past, and is the reason we use this scheme with globals with static linkage and __pure getters.
However, hidden visibility should yield the same results so we should be able to make it work with that instead. However, given the breakage in the past, I don't think it's worth it since the performance gain will be negligible.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
The GCC documentation mentions that it does not make sense for a function annotated as const not to take any arguments, so I'd rather avoid it here.
Where does it say that? I only see it saying it doesn't make sense for it to return void.
Quoted 6 lines
You're right. I looked into this in the past, and I misremembered, and paraphrased it incorrectly.
The documentation does mention that const functions are not permitted to read global memory.
What it says is that "[the const attribute] tells GCC that subsequent calls to function square with the same argument value can be replaced by the result of the first call regardless of the statements in between" and "The const attribute prohibits a function from reading objects that affect its return value between successive invocations. However, functions declared with the attribute can safely read objects that do not change their return value, such as non-volatile constants."
In this case since the globals in question never change after being set, it should be safe -- every call to these functions does return the same value.
Quoted 10 lines
Quoted 3 lines
Currently if we call 5 EFI services in the same function, it has to re-evaluate systemtable and is64 for each call, which seems wasteful, though of course this is not exactly performance-critical code.
The alternative would be to use globals with external linkage in a way that is guaranteed not to rely on GOT entries, since we'll end up with absolute addresses that need to be fixed up first. This has caused breakage in the past, and is the reason we use this scheme with globals with static linkage and
__puregetters.
Quoted 4 lines
However, hidden visibility should yield the same results so we should be able to make it work with that instead. However, given the breakage in the past, I don't think it's worth it since the performance gain will be negligible.
This only saves the overhead of the function call, but the compiler would still have to re-read the variables and re-test them, since so far as it knows the firmware call could change them. With the const function attribute, it will only load them once. To make it work with just the variables, they'd have to be declared const and initialized in the assembly entry code.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 28 lines · Arvind Sankar
Quoted 11 lines · Ard Biesheuvel
Quoted 9 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
The GCC documentation mentions that it does not make sense for a function annotated as const not to take any arguments, so I'd rather avoid it here.
Where does it say that? I only see it saying it doesn't make sense for it to return void.
Quoted 6 lines
You're right. I looked into this in the past, and I misremembered, and paraphrased it incorrectly.
The documentation does mention that const functions are not permitted to read global memory.
What it says is that "[the const attribute] tells GCC that subsequent calls to function square with the same argument value can be replaced by the result of the first call regardless of the statements in between" and "The const attribute prohibits a function from reading objects that affect its return value between successive invocations. However, functions declared with the attribute can safely read objects that do not change their return value, such as non-volatile constants."
Quoted 4 lines
In this case since the globals in question never change after being set, it should be safe -- every call to these functions does return the same value.
I agree that it should be safe. However, the document I looked at literally says
"""
Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.
"""
However, this is actually a fairly old version of the docs [0], and the most recent version seems to permit it.
[0] https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
Quoted 15 lines
Quoted 10 lines
Quoted 3 lines
Currently if we call 5 EFI services in the same function, it has to re-evaluate systemtable and is64 for each call, which seems wasteful, though of course this is not exactly performance-critical code.
The alternative would be to use globals with external linkage in a way that is guaranteed not to rely on GOT entries, since we'll end up with absolute addresses that need to be fixed up first. This has caused breakage in the past, and is the reason we use this scheme with globals with static linkage and
__puregetters.Quoted 4 lines
However, hidden visibility should yield the same results so we should be able to make it work with that instead. However, given the breakage in the past, I don't think it's worth it since the performance gain will be negligible.
Quoted 6 lines
This only saves the overhead of the function call, but the compiler would still have to re-read the variables and re-test them, since so far as it knows the firmware call could change them. With the const function attribute, it will only load them once. To make it work with just the variables, they'd have to be declared const and initialized in the assembly entry code.
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-const
Could you please check if that fixes the issue for efi_is_64bit() ?
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?
Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 5 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Yeah, good point.
Quoted 7 lines
Quoted 4 lines
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of efi_is64, but I am having trouble to reproduce the original issue.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 10 lines · Ard Biesheuvel
Quoted 8 lines · Arvind Sankar
Quoted 6 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-const
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Could you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.
Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 16 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/
I wonder if commit 6d92bc9d483a ("x86/build: Build compressed x86 kernels as PIE") resolved this.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 22 lines · Arvind Sankar
Quoted 20 lines · Ard Biesheuvel
Quoted 18 lines · Ard Biesheuvel
Quoted 5 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Yeah, good point.
Quoted 7 lines
Quoted 4 lines
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.
Quoted 7 lines
Quoted 4 lines
Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/I wonder if commit
6d92bc9d483a("x86/build: Build compressed x86 kernels as PIE") resolved this.
Good question. But note that the stub is still built with -fPIC not -fPIE.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 25 lines · Ard Biesheuvel
Quoted 24 lines · Arvind Sankar
Quoted 22 lines · Ard Biesheuvel
Quoted 10 lines · Ard Biesheuvel
Quoted 8 lines · Arvind Sankar
Quoted 6 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constQuoted 8 lines
Quoted 4 lines
Quoted 1 line
Could you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/I wonder if commit
6d92bc9d483a("x86/build: Build compressed x86 kernels as PIE") resolved this.Good question. But note that the stub is still built with -fPIC not -fPIE.
Hm libstub is -fPIC but arch/x86/boot/compressed is -fPIE. With -fPIE gcc 5+ doesn't use GOTPCREL even with default visibility, but gcc 4.7 does. With -fPIC though you need hidden visibility to avoid GOTPCREL.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
In reply to Ard BiesheuvelQuoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/
OK, I have done a bit more digging, and it seems like recent toolchains can optimize away GOT indirections using R_386_GOT32X relocations, which can be converted into R_386_GOTOFF relocations by the linker if it is building a fully linked binary, making the actual contents of the GOT entries irrelevant.
Note that even if the GOT entries are not fixed up, assigning a global variable and then using it again may work by accident if the memory it points to is writable, which is why it is not easy to reproduce reliably.
efi_is64 only exists on 64-bit, so annotating that as 'hidden' should work. But efi_system_table() is also used on 32-bit, so I'll leave that one alone for now.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 33 lines · Ard Biesheuvel
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/OK, I have done a bit more digging, and it seems like recent toolchains can optimize away GOT indirections using
R_386_GOT32Xrelocations, which can be converted intoR_386_GOTOFFrelocations by the linker if it is building a fully linked binary, making the actual contents of the GOT entries irrelevant.
Quoted 8 lines
Note that even if the GOT entries are not fixed up, assigning a global variable and then using it again may work by accident if the memory it points to is writable, which is why it is not easy to reproduce reliably.
efi_is64only exists on 64-bit, so annotating that as 'hidden' should work. Butefi_system_table()is also used on 32-bit, so I'll leave that one alone for now.
With hidden visibility, 32-bit compiler seems to generate GOTOFF relocations directly so it shouldn't depend on recent toolchain?
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 40 lines · Arvind Sankar
Quoted 38 lines · Ard Biesheuvel
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/OK, I have done a bit more digging, and it seems like recent toolchains can optimize away GOT indirections using
R_386_GOT32Xrelocations, which can be converted intoR_386_GOTOFFrelocations by the linker if it is building a fully linked binary, making the actual contents of the GOT entries irrelevant.Note that even if the GOT entries are not fixed up, assigning a global variable and then using it again may work by accident if the memory it points to is writable, which is why it is not easy to reproduce reliably.
Quoted 8 lines
Quoted 3 lines
efi_is64only exists on 64-bit, so annotating that as 'hidden' should work. Butefi_system_table()is also used on 32-bit, so I'll leave that one alone for now.With hidden visibility, 32-bit compiler seems to generate GOTOFF relocations directly so it shouldn't depend on recent toolchain?
Yes, that was my assumption at the time as well, but we still ended up with /some/ absolute GOT dereferences for some reason in the 32-bit kernel.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 45 lines · Ard Biesheuvel
Quoted 44 lines · Arvind Sankar
Quoted 41 lines · Ard Biesheuvel
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/OK, I have done a bit more digging, and it seems like recent toolchains can optimize away GOT indirections using
R_386_GOT32Xrelocations, which can be converted intoR_386_GOTOFFrelocations by the linker if it is building a fully linked binary, making the actual contents of the GOT entries irrelevant.Note that even if the GOT entries are not fixed up, assigning a global variable and then using it again may work by accident if the memory it points to is writable, which is why it is not easy to reproduce reliably.
efi_is64only exists on 64-bit, so annotating that as 'hidden' should work. Butefi_system_table()is also used on 32-bit, so I'll leave that one alone for now.
Quoted 8 lines
Quoted 4 lines
With hidden visibility, 32-bit compiler seems to generate GOTOFF relocations directly so it shouldn't depend on recent toolchain?
Yes, that was my assumption at the time as well, but we still ended up with /some/ absolute GOT dereferences for some reason in the 32-bit kernel.
Do you remember if we ever figured out what was wrong with Matt Fleming's patch to fixup the GOT for the EFI stub too?
For efi_system_table, if we don't want to risk creating GOT entries, one option would be to do what you did for is64, but define the wrapper function as an out-of-line function in the assembler code and declare it const.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 50 lines · Arvind Sankar
Quoted 48 lines · Ard Biesheuvel
Quoted 47 lines · Arvind Sankar
Quoted 33 lines · Ard Biesheuvel
Quoted 17 lines · Ard Biesheuvel
Quoted 15 lines · Ard Biesheuvel
Quoted 12 lines · Arvind Sankar
Quoted 7 lines · Ard Biesheuvel
Yeah, good point.
I pushed as branch here;
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-libstub-attr-constCould you please check if that fixes the issue for
efi_is_64bit()?Haven't built it yet -- but how does this handle the GOT issues you mentioned?
Quoted 8 lines
Quoted 3 lines
It doesn't. The trick is to add __attribute__((visibility("hidden"))) to the extern declaration of
efi_is64, but I am having trouble to reproduce the original issue.Some background:
https://lore.kernel.org/lkml/[email protected]/
https://lore.kernel.org/lkml/[email protected]/OK, I have done a bit more digging, and it seems like recent toolchains can optimize away GOT indirections using
R_386_GOT32Xrelocations, which can be converted intoR_386_GOTOFFrelocations by the linker if it is building a fully linked binary, making the actual contents of the GOT entries irrelevant.Quoted 8 lines
Note that even if the GOT entries are not fixed up, assigning a global variable and then using it again may work by accident if the memory it points to is writable, which is why it is not easy to reproduce reliably.
efi_is64only exists on 64-bit, so annotating that as 'hidden' should work. Butefi_system_table()is also used on 32-bit, so I'll leave that one alone for now.With hidden visibility, 32-bit compiler seems to generate GOTOFF relocations directly so it shouldn't depend on recent toolchain?
Quoted 9 lines
Quoted 5 lines
Quoted 1 line
Yes, that was my assumption at the time as well, but we still ended up with /some/ absolute GOT dereferences for some reason in the 32-bit kernel.
Do you remember if we ever figured out what was wrong with Matt Fleming's patch to fixup the GOT for the EFI stub too?
No, I don't think we did. It is simply infeasible to diagnose this on someone else's laptop who is on the other side of the world.
Quoted 4 lines
For
efi_system_table, if we don't want to risk creating GOT entries, one option would be to do what you did for is64, but define the wrapper function as an out-of-line function in the assembler code and declare it const.
Yeah, that would work. It would be for 32-bit only, so we could have a __weak implementation in C, and an asm one for i386.
Currently, I am not managing to get the 64-bit compiler to emit any GOT based references for efi_is64, though, even without the attribute, so I am not sure what's going on there.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 3 lines · Ard Biesheuvel
Currently, I am not managing to get the 64-bit compiler to emit any GOT based references for
efi_is64, though, even without the attribute, so I am not sure what's going on there.
With gcc 9, I do get R_X86_64_REX_GOTPCRELX relocations in libstub, which are then eliminated by the linker -- if they weren't they would be using addresses from the GOT. They turn into R_X86_64_PC32 with the hidden visibility.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 10 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Currently, I am not managing to get the 64-bit compiler to emit any GOT based references for
efi_is64, though, even without the attribute, so I am not sure what's going on there.With gcc 9, I do get
R_X86_64_REX_GOTPCRELXrelocations in libstub, which are then eliminated by the linker -- if they weren't they would be using addresses from the GOT. They turn intoR_X86_64_PC32with the hidden visibility.
Indeed. I was looking at eboot.o but that gets built with -fPIE not -fPIC [if available].
libstub objects indeed have the R_X86_64_REX_GOTPCRELX relocations, so I'll add the hidden visibility to the extern declaration of efi_is64
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 12 lines · Ard Biesheuvel
Quoted 10 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Currently, I am not managing to get the 64-bit compiler to emit any GOT based references for
efi_is64, though, even without the attribute, so I am not sure what's going on there.With gcc 9, I do get
R_X86_64_REX_GOTPCRELXrelocations in libstub, which are then eliminated by the linker -- if they weren't they would be using addresses from the GOT. They turn intoR_X86_64_PC32with the hidden visibility.
Quoted 5 lines
Indeed. I was looking at eboot.o but that gets built with -fPIE not -fPIC [if available].
libstub objects indeed have the
R_X86_64_REX_GOTPCRELXrelocations, so I'll add the hidden visibility to the extern declaration ofefi_is64
Is there any reason not to compile the stub with -fPIE btw? Also fPIE seems to be there even in gcc 4.1.2, the check for availability can probably be dropped.
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
Quoted 17 lines · Arvind Sankar
Quoted 15 lines · Ard Biesheuvel
Quoted 10 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Currently, I am not managing to get the 64-bit compiler to emit any GOT based references for
efi_is64, though, even without the attribute, so I am not sure what's going on there.With gcc 9, I do get
R_X86_64_REX_GOTPCRELXrelocations in libstub, which are then eliminated by the linker -- if they weren't they would be using addresses from the GOT. They turn intoR_X86_64_PC32with the hidden visibility.Indeed. I was looking at eboot.o but that gets built with -fPIE not -fPIC [if available].
Quoted 6 lines
Quoted 2 lines
libstub objects indeed have the
R_X86_64_REX_GOTPCRELXrelocations, so I'll add the hidden visibility to the extern declaration ofefi_is64Is there any reason not to compile the stub with -fPIE btw? Also fPIE seems to be there even in gcc 4.1.2, the check for availability can probably be dropped.
No we should switch to -fPIE for the stub as well
Re: [PATCH v2 13/21] efi/libstub/x86: drop __efi_early() export of efi_config struct
In reply to Ard BiesheuvelQuoted 8 lines · Ard Biesheuvel
Quoted 4 lines
Do you remember if we ever figured out what was wrong with Matt Fleming's patch to fixup the GOT for the EFI stub too?
No, I don't think we did. It is simply infeasible to diagnose this on someone else's laptop who is on the other side of the world.
Hm looking at that code, I think it wouldn't do the GOT relocation adjustment needed after copying the kernel for decompression. But then it shouldn't have worked at all presumably...
Maybe we should just try again and see if it breaks anyone.
Ard Biesheuvel
maintainerPATCH v2 14/21 efi/libstub: drop sys_table_arg from printk routines
In reply to Ard BiesheuvelAs a first step towards getting rid of the need to pass around a function parameter 'sys_table_arg' pointing to the EFI system table, remove the references to it in the printing code, which is represents the majority of the use cases.
--- arch/x86/boot/compressed/eboot.c | 28 +++++++-------- drivers/firmware/efi/libstub/arm-stub.c | 28 +++++++-------- drivers/firmware/efi/libstub/arm32-stub.c | 14 ++++---- drivers/firmware/efi/libstub/arm64-stub.c | 12 +++---- drivers/firmware/efi/libstub/efi-stub-helper.c | 37 ++++++++++---------- drivers/firmware/efi/libstub/efistub.h | 9 ++--- drivers/firmware/efi/libstub/fdt.c | 16 ++++----- drivers/firmware/efi/libstub/secureboot.c | 4 +-- drivers/firmware/efi/libstub/tpm.c | 3 +- include/linux/efi.h | 2 +- 10 files changed, 75 insertions(+), 78 deletions(-)
arch/x86/boot/compressed/eboot.c +14 -14
@@ -64,7 +64,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__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" ); +efi_printk ("Failed to allocate memory for 'rom'\n" );return status; }
@@ -81,7 +81,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) &rom->vendor);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to read rom->vendor\n" ); +efi_printk ("Failed to read rom->vendor\n" ); goto free_struct; }
@@ -90,7 +90,7 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) &rom->devid);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to read rom->devid\n" ); +efi_printk ("Failed to read rom->devid\n" ); goto free_struct; }
@@ -139,7 +139,7 @@ static void setup_efi_pci(struct boot_params *params) size, (void **)&pci_handle);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to allocate memory for 'pci_handle'\n" ); +efi_printk ("Failed to allocate memory for 'pci_handle'\n" );return ; }
@@ -194,7 +194,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)return ;if (efi_table_attr (apple_properties_protocol, version, p) !=0x10000 ) { -efi_printk (sys_table,"Unsupported properties proto version\n" ); +efi_printk ("Unsupported properties proto version\n" );return ; }
@@ -207,7 +207,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params) size +sizeof (struct setup_data ), (void **)&new);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to allocate memory for 'properties'\n" ); +efi_printk ("Failed to allocate memory for 'properties'\n" );return ; }
@@ -392,14 +392,14 @@ struct boot_params *make_boot_params(struct efi_config *c) status =efi_call_early (handle_protocol, handle, &proto, (void *)&image);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to get handle for LOADED_IMAGE_PROTOCOL\n" ); +efi_printk ("Failed to get handle for LOADED_IMAGE_PROTOCOL\n" );return NULL ; } status =efi_low_alloc (sys_table,0x4000 ,1 , (unsigned long *)&boot_params);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to allocate lowmem for boot params\n" ); +efi_printk ("Failed to allocate lowmem for boot params\n" );return NULL ; }
@@ -447,7 +447,7 @@ struct boot_params *make_boot_params(struct efi_config *c)if (status !=EFI_SUCCESS && hdr->xloadflags &XLF_CAN_BE_LOADED_ABOVE_4G ) { -efi_printk (sys_table,"Trying to load files to higher address\n" ); +efi_printk ("Trying to load files to higher address\n" ); status = handle_cmdline_files(sys_table, image, (char *)(unsigned long)hdr->cmd_line_ptr, "initrd=", -1UL,
@@ -777,7 +777,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) status =efi_call_early (allocate_pool,EFI_LOADER_DATA ,sizeof (*gdt), (void **)&gdt);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to allocate memory for 'gdt' structure\n" ); +efi_printk ("Failed to allocate memory for 'gdt' structure\n" ); goto fail; }
@@ -785,7 +785,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) status =efi_low_alloc (sys_table, gdt->size,8 , (unsigned long *)&gdt->address);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"Failed to allocate memory for 'gdt'\n" ); +efi_printk ("Failed to allocate memory for 'gdt'\n" ); goto fail; }
@@ -801,7 +801,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) hdr->kernel_alignment, LOAD_PHYSICAL_ADDR);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"efi_relocate_kernel() failed!\n" ); +efi_printk ("efi_relocate_kernel() failed!\n" ); goto fail; }
@@ -811,7 +811,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) status =exit_boot (boot_params, handle);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table,"exit_boot() failed!\n" ); +efi_printk ("exit_boot() failed!\n" ); goto fail; }
@@ -904,7 +904,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)return boot_params; fail: -efi_printk (sys_table,"efi_main() failed!\n" ); +efi_printk ("efi_main() failed!\n" );return NULL ; }
drivers/firmware/efi/libstub/arm-stub.c +14 -14
@@ -73,7 +73,7 @@ void install_memreserve_table(efi_system_table_t *sys_table_arg) status =efi_call_early (allocate_pool,EFI_LOADER_DATA ,sizeof (*rsv), (void **)&rsv);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to allocate memreserve entry!\n" ); +pr_efi_err ("Failed to allocate memreserve entry!\n" );return ; }
@@ -85,7 +85,7 @@ void install_memreserve_table(efi_system_table_t *sys_table_arg) &memreserve_table_guid, rsv);if (status !=EFI_SUCCESS ) -pr_efi_err (sys_table_arg,"Failed to install memreserve config table!\n" ); +pr_efi_err ("Failed to install memreserve config table!\n" ); }
@@ -147,13 +147,13 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg, status = sys_table->boottime->handle_protocol (handle, &loaded_image_proto, (void *)&image);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Failed to get loaded image protocol\n" ); +pr_efi_err ("Failed to get loaded image protocol\n" ); goto fail; } dram_base =get_dram_base (sys_table);if (dram_base ==EFI_ERROR ) { -pr_efi_err (sys_table,"Failed to find DRAM base\n" ); +pr_efi_err ("Failed to find DRAM base\n" ); goto fail; }
@@ -164,7 +164,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,*/ cmdline_ptr =efi_convert_cmdline (sys_table, image, &cmdline_size);if (!cmdline_ptr) { -pr_efi_err (sys_table,"getting command line via LOADED_IMAGE_PROTOCOL\n" ); +pr_efi_err ("getting command line via LOADED_IMAGE_PROTOCOL\n" ); goto fail; }
@@ -176,7 +176,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,if (!IS_ENABLED (CONFIG_CMDLINE_FORCE ) && cmdline_size >0 )efi_parse_options (cmdline_ptr); -pr_efi (sys_table,"Booting Linux Kernel...\n" ); +pr_efi ("Booting Linux Kernel...\n" ); si =setup_graphics (sys_table);
@@ -185,7 +185,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg, &reserve_size, dram_base, image);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Failed to relocate kernel\n" ); +pr_efi_err ("Failed to relocate kernel\n" ); goto fail_free_cmdline; }
@@ -204,29 +204,29 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,if (!IS_ENABLED (CONFIG_EFI_ARMSTUB_DTB_LOADER ) || secure_boot != efi_secureboot_mode_disabled) {if (strstr (cmdline_ptr,"dtb=" )) -pr_efi (sys_table,"Ignoring DTB from command line.\n" ); +pr_efi ("Ignoring DTB from command line.\n" ); }else { status =handle_cmdline_files (sys_table, image, cmdline_ptr,"dtb=" , ~0UL , &fdt_addr, &fdt_size);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Failed to load device tree!\n" ); +pr_efi_err ("Failed to load device tree!\n" ); goto fail_free_image; } }if (fdt_addr) { -pr_efi (sys_table,"Using DTB from command line\n" ); +pr_efi ("Using DTB from command line\n" ); }else {/* Look for a device tree configuration table entry. */ fdt_addr = (uintptr_t )get_fdt (sys_table, &fdt_size);if (fdt_addr) -pr_efi (sys_table,"Using DTB from configuration table\n" ); +pr_efi ("Using DTB from configuration table\n" ); }if (!fdt_addr) -pr_efi (sys_table,"Generating empty DTB\n" ); +pr_efi ("Generating empty DTB\n" ); status = handle_cmdline_files(sys_table, image, cmdline_ptr, "initrd=", efi_get_max_initrd_addr(dram_base,
@@ -234,7 +234,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg, (unsigned long *)&initrd_addr, (unsigned long *)&initrd_size);if (status !=EFI_SUCCESS ) -pr_efi_err (sys_table,"Failed initrd from command line!\n" ); +pr_efi_err ("Failed initrd from command line!\n" );efi_random_get_seed (sys_table);
@@ -275,7 +275,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,if (status ==EFI_SUCCESS )return new_fdt_addr; -pr_efi_err (sys_table,"Failed to update FDT and exit boot services\n" ); +pr_efi_err ("Failed to update FDT and exit boot services\n" );efi_free (sys_table, initrd_size, initrd_addr);efi_free (sys_table, fdt_size, fdt_addr);
drivers/firmware/efi/libstub/arm32-stub.c +6 -8
@@ -18,7 +18,7 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)/* LPAE kernels need compatible hardware */ block =cpuid_feature_extract (CPUID_EXT_MMFR0 ,0 );if (block <5 ) { -pr_efi_err (sys_table_arg,"This LPAE kernel is not supported by your CPU\n" ); +pr_efi_err ("This LPAE kernel is not supported by your CPU\n" );return EFI_UNSUPPORTED ; }return EFI_SUCCESS ;
@@ -121,8 +121,7 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,*/ status =efi_get_memory_map (sys_table_arg, &map);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg, -"reserve_kernel_base(): Unable to retrieve memory map.\n" ); +pr_efi_err ("reserve_kernel_base(): Unable to retrieve memory map.\n" );return status; }
@@ -164,8 +163,7 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg, (end - start) /EFI_PAGE_SIZE , &start);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg, -"reserve_kernel_base(): alloc failed.\n" ); +pr_efi_err ("reserve_kernel_base(): alloc failed.\n" ); goto out; }break ;
@@ -224,7 +222,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, status =reserve_kernel_base (sys_table, kernel_base, reserve_addr, reserve_size);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Unable to allocate memory for uncompressed kernel.\n" ); +pr_efi_err ("Unable to allocate memory for uncompressed kernel.\n" );return status; }
@@ -237,7 +235,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table, *image_size, kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Failed to relocate kernel.\n" ); +pr_efi_err ("Failed to relocate kernel.\n" );efi_free (sys_table, *reserve_size, *reserve_addr); *reserve_size =0 ;return status;
@@ -249,7 +247,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,* address at which the zImage is loaded. */ if (*image_addr + *image_size > dram_base +ZIMAGE_OFFSET_LIMIT ) { -pr_efi_err (sys_table,"Failed to relocate kernel, no low memory available.\n" ); +pr_efi_err ("Failed to relocate kernel, no low memory available.\n" );efi_free (sys_table, *reserve_size, *reserve_addr); *reserve_size =0 ;efi_free (sys_table, *image_size, *image_addr);
drivers/firmware/efi/libstub/arm64-stub.c +6 -6
@@ -32,9 +32,9 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg) tg = (read_cpuid (ID_AA64MMFR0_EL1 ) >>ID_AA64MMFR0_TGRAN_SHIFT ) &0xf ;if (tg !=ID_AA64MMFR0_TGRAN_SUPPORTED ) {if (IS_ENABLED (CONFIG_ARM64_64K_PAGES )) -pr_efi_err (sys_table_arg,"This 64 KB granular kernel is not supported by your CPU\n" ); +pr_efi_err ("This 64 KB granular kernel is not supported by your CPU\n" );else -pr_efi_err (sys_table_arg,"This 16 KB granular kernel is not supported by your CPU\n" ); +pr_efi_err ("This 16 KB granular kernel is not supported by your CPU\n" );return EFI_UNSUPPORTED ; }return EFI_SUCCESS ;
@@ -60,13 +60,13 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,sizeof (phys_seed), (u8 *)&phys_seed);if (status ==EFI_NOT_FOUND ) { -pr_efi (sys_table_arg,"EFI_RNG_PROTOCOL unavailable, no randomness supplied\n" ); +pr_efi ("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n" ); }else if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"efi_get_random_bytes() failed\n" ); +pr_efi_err ("efi_get_random_bytes() failed\n" );return status; } }else { -pr_efi (sys_table_arg,"KASLR disabled on kernel command line\n" ); +pr_efi ("KASLR disabled on kernel command line\n" ); } }
@@ -143,7 +143,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, MIN_KIMG_ALIGN, reserve_addr);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to relocate kernel\n" ); +pr_efi_err ("Failed to relocate kernel\n" ); *reserve_size =0 ;return status; }
drivers/firmware/efi/libstub/efi-stub-helper.c +18 -19
@@ -58,7 +58,7 @@ struct file_info {u64 size; }; -void efi_printk (efi_system_table_t *sys_table_arg,char *str) +void efi_printk (char *str) {char *s8;
@@ -68,10 +68,10 @@ void efi_printk(efi_system_table_t *sys_table_arg, char *str) ch[0 ] = *s8;if (*s8 =='\n' ) {efi_char16_t nl[2 ] = {'\r' ,0 }; -efi_char16_printk (sys_table_arg, nl); +efi_char16_printk (nl); } -efi_char16_printk (sys_table_arg, ch); +efi_char16_printk (ch); } }
@@ -378,9 +378,9 @@ static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, status =efi_call_proto (efi_file_handle, open, fh, &h, filename_16,EFI_FILE_MODE_READ , (u64 )0 );if (status !=EFI_SUCCESS ) { -efi_printk (sys_table_arg,"Failed to open file: " ); -efi_char16_printk (sys_table_arg, filename_16); -efi_printk (sys_table_arg,"\n" ); +efi_printk ("Failed to open file: " ); +efi_char16_printk (filename_16); +efi_printk ("\n" );return status; }
@@ -390,7 +390,7 @@ static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, status =efi_call_proto (efi_file_handle, get_info, h, &info_guid, &info_sz,NULL );if (status !=EFI_BUFFER_TOO_SMALL ) { -efi_printk (sys_table_arg,"Failed to get file info size\n" ); +efi_printk ("Failed to get file info size\n" );return status; }
@@ -398,7 +398,7 @@ static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, status =efi_call_early (allocate_pool,EFI_LOADER_DATA , info_sz, (void **)&info);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table_arg,"Failed to alloc mem for file info\n" ); +efi_printk ("Failed to alloc mem for file info\n" );return status; }
@@ -413,7 +413,7 @@ static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,efi_call_early (free_pool, info);if (status !=EFI_SUCCESS ) -efi_printk (sys_table_arg,"Failed to get initrd info\n" ); +efi_printk ("Failed to get initrd info\n" );return status; }
@@ -442,13 +442,13 @@ static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, status =efi_call_early (handle_protocol, handle, &fs_proto, (void **)&io);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table_arg,"Failed to handle fs_proto\n" ); +efi_printk ("Failed to handle fs_proto\n" );return status; } status =efi_call_proto (efi_file_io_interface, open_volume, io, &fh);if (status !=EFI_SUCCESS ) -efi_printk (sys_table_arg,"Failed to open volume\n" ); +efi_printk ("Failed to open volume\n" );else *__fh = fh;
@@ -547,8 +547,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,* by the thunking code. */ if (!efi_is_native ()) { -pr_efi (sys_table_arg, -"Ignoring file= arguments on mixed mode system\n" ); +pr_efi ("Ignoring file= arguments on mixed mode system\n" );return EFI_SUCCESS ; }
@@ -589,7 +588,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, status =efi_call_early (allocate_pool,EFI_LOADER_DATA , nr_files *sizeof (*files), (void **)&files);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to alloc mem for file handle list\n" ); +pr_efi_err ("Failed to alloc mem for file handle list\n" ); goto fail; }
@@ -652,13 +651,13 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, status =efi_high_alloc (sys_table_arg, file_size_total,0x1000 , &file_addr, max_addr);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to alloc highmem for files\n" ); +pr_efi_err ("Failed to alloc highmem for files\n" ); goto close_handles; }/* We've run out of free low memory. */ if (file_addr > max_addr) { -pr_efi_err (sys_table_arg,"We've run out of free low memory\n" ); +pr_efi_err ("We've run out of free low memory\n" ); status =EFI_INVALID_PARAMETER ; goto free_file_total; }
@@ -680,7 +679,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, &chunksize, (void *)addr);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to read file\n" ); +pr_efi_err ("Failed to read file\n" ); goto free_file_total; } addr += chunksize;
@@ -766,7 +765,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, alignment, &new_addr, min_addr); }if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table_arg,"Failed to allocate usable memory for kernel.\n" ); +pr_efi_err ("Failed to allocate usable memory for kernel.\n" );return status; }
@@ -976,7 +975,7 @@ void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid)return NULL ; } -void efi_char16_printk (efi_system_table_t *table,efi_char16_t *str) +void efi_char16_printk (efi_char16_t *str) { efi_call_proto(efi_simple_text_output_protocol, output_string,
drivers/firmware/efi/libstub/efistub.h +5 -4
@@ -31,13 +31,14 @@ extern int __pure novamap(void);extern __pure efi_system_table_t *efi_system_table (void ); -#define pr_efi (sys_table, msg) do { \ - if (!is_quiet()) efi_printk(sys_table, "EFI stub: "msg); \ +#define pr_efi (msg) do { \ + if (!is_quiet()) efi_printk("EFI stub: "msg); \ } while (0) -#define pr_efi_err (sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) +#define pr_efi_err (msg) efi_printk("EFI stub: ERROR: "msg) -void efi_char16_printk (efi_system_table_t *,efi_char16_t *); +void efi_char16_printk (efi_char16_t *); +void efi_char16_printk (efi_char16_t *);unsigned long get_dram_base (efi_system_table_t *sys_table_arg);
drivers/firmware/efi/libstub/fdt.c +8 -8
@@ -40,7 +40,7 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,/* Do some checks on provided FDT, if it exists: */ if (orig_fdt) {if (fdt_check_header (orig_fdt)) { -pr_efi_err (sys_table,"Device Tree header not valid!\n" ); +pr_efi_err ("Device Tree header not valid!\n" );return EFI_LOAD_ERROR ; }/*
@@ -48,7 +48,7 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,* configuration table: */ if (orig_fdt_size &&fdt_totalsize (orig_fdt) > orig_fdt_size) { -pr_efi_err (sys_table,"Truncated device tree! foo!\n" ); +pr_efi_err ("Truncated device tree! foo!\n" );return EFI_LOAD_ERROR ; } }
@@ -277,17 +277,17 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,*/ status =efi_get_memory_map (sys_table, &map);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Unable to retrieve UEFI memory map.\n" ); +pr_efi_err ("Unable to retrieve UEFI memory map.\n" );return status; } -pr_efi (sys_table,"Exiting boot services and installing virtual address map...\n" ); +pr_efi ("Exiting boot services and installing virtual address map...\n" ); map.map = &memory_map; status =efi_high_alloc (sys_table,MAX_FDT_SIZE ,EFI_FDT_ALIGN , new_fdt_addr, max_addr);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Unable to allocate memory for new device tree.\n" ); +pr_efi_err ("Unable to allocate memory for new device tree.\n" ); goto fail; }
@@ -304,7 +304,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, initrd_addr, initrd_size);if (status !=EFI_SUCCESS ) { -pr_efi_err (sys_table,"Unable to construct new device tree.\n" ); +pr_efi_err ("Unable to construct new device tree.\n" ); goto fail_free_new_fdt; }
@@ -350,7 +350,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,return EFI_SUCCESS ; } -pr_efi_err (sys_table,"Exit boot services failed.\n" ); +pr_efi_err ("Exit boot services failed.\n" ); fail_free_new_fdt:efi_free (sys_table,MAX_FDT_SIZE , *new_fdt_addr);
@@ -371,7 +371,7 @@ void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)return NULL ;if (fdt_check_header (fdt) !=0 ) { -pr_efi_err (sys_table,"Invalid header detected on UEFI supplied FDT, ignoring ...\n" ); +pr_efi_err ("Invalid header detected on UEFI supplied FDT, ignoring ...\n" );return NULL ; } *fdt_size =fdt_totalsize (fdt);
drivers/firmware/efi/libstub/secureboot.c +2 -2
@@ -72,10 +72,10 @@ enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg)return efi_secureboot_mode_disabled; secure_boot_enabled: -pr_efi (sys_table_arg,"UEFI Secure Boot is enabled.\n" ); +pr_efi ("UEFI Secure Boot is enabled.\n" );return efi_secureboot_mode_enabled; out_efi_err: -pr_efi_err (sys_table_arg,"Could not determine UEFI Secure Boot status.\n" ); +pr_efi_err ("Could not determine UEFI Secure Boot status.\n" );return efi_secureboot_mode_unknown; }
drivers/firmware/efi/libstub/tpm.c +1 -2
@@ -131,8 +131,7 @@ void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg) (void **) &log_tbl);if (status !=EFI_SUCCESS ) { -efi_printk (sys_table_arg, -"Unable to allocate memory for event log\n" ); +efi_printk ("Unable to allocate memory for event log\n" );return ; }
include/linux/efi.h +1 -1
@@ -1551,7 +1551,7 @@ static inline int efi_runtime_map_copy(void *buf, size_t bufsz)/* prototypes shared between arch specific and generic stub code */ -void efi_printk (efi_system_table_t *sys_table_arg,char *str); +void efi_printk (char *str);void efi_free (efi_system_table_t *sys_table_arg,unsigned long size,unsigned long addr);
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 15/21 efi/libstub: remove 'sys_table_arg' from all function prototypes
In reply to Ard BiesheuvelWe have a helper efi_system_table() that gives us the address of the EFI system table in memory, so there is no longer point in passing it around from each function to the next.
--- arch/arm/include/asm/efi.h | 4 +- arch/arm64/include/asm/efi.h | 3 +- arch/x86/boot/compressed/eboot.c | 40 +++++------ drivers/firmware/efi/libstub/arm-stub.c | 55 +++++++-------- drivers/firmware/efi/libstub/arm32-stub.c | 26 +++---- drivers/firmware/efi/libstub/arm64-stub.c | 12 ++-- drivers/firmware/efi/libstub/efi-stub-helper.c | 74 +++++++++----------- drivers/firmware/efi/libstub/efistub.h | 17 ++--- drivers/firmware/efi/libstub/fdt.c | 37 +++++----- drivers/firmware/efi/libstub/gop.c | 10 ++- drivers/firmware/efi/libstub/random.c | 10 ++- drivers/firmware/efi/libstub/secureboot.c | 2 +- drivers/firmware/efi/libstub/tpm.c | 5 +- include/linux/efi.h | 43 +++++------- 14 files changed, 147 insertions(+), 191 deletions(-)
arch/arm/include/asm/efi.h +2 -2
@@ -60,8 +60,8 @@ void efi_virtmap_unload(void);#define efi_call_proto (protocol, f, instance, ...) \ instance->f(instance, ##__VA_ARGS__) -struct screen_info *alloc_screen_info (efi_system_table_t *sys_table_arg); -void free_screen_info (efi_system_table_t *sys_table,struct screen_info *si); +struct screen_info *alloc_screen_info (void ); +void free_screen_info (struct screen_info *si);static inline void efifb_setup_from_dmi (struct screen_info *si,const char *opt) {
arch/arm64/include/asm/efi.h +1 -2
@@ -105,8 +105,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, #define alloc_screen_info(x...) &screen_info -static inline void free_screen_info (efi_system_table_t *sys_table_arg, -struct screen_info *si) +static inline void free_screen_info (struct screen_info *si) { }
arch/x86/boot/compressed/eboot.c +18 -22
@@ -347,7 +347,7 @@ void setup_graphics(struct boot_params *boot_params)EFI_LOCATE_BY_PROTOCOL , &graphics_proto, NULL, &size, gop_handle);if (status ==EFI_BUFFER_TOO_SMALL ) - status =efi_setup_gop (NULL , si, &graphics_proto, size); + status =efi_setup_gop (si, &graphics_proto, size);if (status !=EFI_SUCCESS ) { size =0 ;
@@ -396,8 +396,7 @@ struct boot_params *make_boot_params(struct efi_config *c)return NULL ; } - status =efi_low_alloc (sys_table,0x4000 ,1 , - (unsigned long *)&boot_params); + status =efi_low_alloc (0x4000 ,1 , (unsigned long *)&boot_params);if (status !=EFI_SUCCESS ) {efi_printk ("Failed to allocate lowmem for boot params\n" );return NULL ;
@@ -422,7 +421,7 @@ struct boot_params *make_boot_params(struct efi_config *c) hdr->type_of_loader =0x21 ;/* Convert unicode cmdline to ascii */ - cmdline_ptr =efi_convert_cmdline (sys_table, image, &options_size); + cmdline_ptr =efi_convert_cmdline (image, &options_size);if (!cmdline_ptr) goto fail;
@@ -440,7 +439,7 @@ struct boot_params *make_boot_params(struct efi_config *c)if (status !=EFI_SUCCESS ) goto fail2; - status =handle_cmdline_files (sys_table, image, + status =handle_cmdline_files (image, (char *)(unsigned long )hdr->cmd_line_ptr,"initrd=" , hdr->initrd_addr_max, &ramdisk_addr, &ramdisk_size);
@@ -448,7 +447,7 @@ struct boot_params *make_boot_params(struct efi_config *c)if (status !=EFI_SUCCESS && hdr->xloadflags &XLF_CAN_BE_LOADED_ABOVE_4G ) {efi_printk ("Trying to load files to higher address\n" ); - status =handle_cmdline_files (sys_table, image, + status =handle_cmdline_files (image, (char *)(unsigned long )hdr->cmd_line_ptr,"initrd=" ,-1UL , &ramdisk_addr, &ramdisk_size);
@@ -464,9 +463,9 @@ struct boot_params *make_boot_params(struct efi_config *c)return boot_params; fail2: -efi_free (sys_table, options_size, hdr->cmd_line_ptr); +efi_free (options_size, hdr->cmd_line_ptr); fail: -efi_free (sys_table,0x4000 , (unsigned long )boot_params); +efi_free (0x4000 , (unsigned long )boot_params);return NULL ; }
@@ -633,7 +632,7 @@ static efi_status_t allocate_e820(struct boot_params *params, boot_map.key_ptr =NULL ; boot_map.buff_size = &buff_size; - status =efi_get_memory_map (sys_table, &boot_map); + status =efi_get_memory_map (&boot_map);if (status !=EFI_SUCCESS )return status;
@@ -655,8 +654,7 @@ struct exit_boot_struct {struct efi_info *efi; }; -static efi_status_t exit_boot_func (efi_system_table_t *sys_table_arg, -struct efi_boot_memmap *map, +static efi_status_t exit_boot_func (struct efi_boot_memmap *map,void *priv) {const char *signature;
@@ -666,14 +664,14 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, : EFI32_LOADER_SIGNATURE;memcpy (&p->efi->efi_loader_signature, signature,sizeof (__u32)); - p->efi->efi_systab = (unsigned long )sys_table_arg; + p->efi->efi_systab = (unsigned long )efi_system_table (); p->efi->efi_memdesc_size = *map->desc_size; p->efi->efi_memdesc_version = *map->desc_ver; p->efi->efi_memmap = (unsigned long )*map->map; p->efi->efi_memmap_size = *map->map_size;#ifdef CONFIG_X86_64 - p->efi->efi_systab_hi = (unsigned long )sys_table_arg >>32 ; + p->efi->efi_systab_hi = (unsigned long )efi_system_table () >>32 ; p->efi->efi_memmap_hi = (unsigned long )*map->map >>32 ;#endif
@@ -705,8 +703,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)return status;/* Might as well exit boot services now */ - status =efi_exit_boot_services (sys_table, handle, &map, &priv, - exit_boot_func); + status =efi_exit_boot_services (handle, &map, &priv, exit_boot_func);if (status !=EFI_SUCCESS )return status;
@@ -759,14 +756,14 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)* otherwise we ask the BIOS. */ if (boot_params->secure_boot == efi_secureboot_mode_unset) - boot_params->secure_boot =efi_get_secureboot (sys_table); + boot_params->secure_boot =efi_get_secureboot ();/* Ask the firmware to clear memory on unclean shutdown */ -efi_enable_reset_attack_mitigation (sys_table); +efi_enable_reset_attack_mitigation (); -efi_random_get_seed (sys_table); +efi_random_get_seed (); -efi_retrieve_tpm2_eventlog (sys_table); +efi_retrieve_tpm2_eventlog ();setup_graphics (boot_params);
@@ -782,8 +779,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) } gdt->size =0x800 ; - status =efi_low_alloc (sys_table, gdt->size,8 , - (unsigned long *)&gdt->address); + status =efi_low_alloc (gdt->size,8 , (unsigned long *)&gdt->address);if (status !=EFI_SUCCESS ) {efi_printk ("Failed to allocate memory for 'gdt'\n" ); goto fail;
@@ -795,7 +791,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params)*/ if (hdr->pref_address != hdr->code32_start) {unsigned long bzimage_addr = hdr->code32_start; - status = efi_relocate_kernel(sys_table, &bzimage_addr, + status = efi_relocate_kernel(&bzimage_addr, hdr->init_size, hdr->init_size, hdr->pref_address, hdr->kernel_alignment,
drivers/firmware/efi/libstub/arm-stub.c +26 -29
160 lines not on this page · raw message
drivers/firmware/efi/libstub/arm32-stub.c +11 -15
@@ -7,7 +7,7 @@#include "efistub.h" -efi_status_t check_platform_features (efi_system_table_t *sys_table_arg) +efi_status_t check_platform_features (void ) {int block;
@@ -26,7 +26,7 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)static efi_guid_t screen_info_guid =LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID ; -struct screen_info *alloc_screen_info (efi_system_table_t *sys_table_arg) +struct screen_info *alloc_screen_info (void ) {struct screen_info *si;efi_status_t status;
@@ -52,7 +52,7 @@ struct screen_info *alloc_screen_info(efi_system_table_t *sys_table_arg)return NULL ; } -void free_screen_info (efi_system_table_t *sys_table_arg,struct screen_info *si) +void free_screen_info (struct screen_info *si) {if (!si)return ;
@@ -61,8 +61,7 @@ void free_screen_info(efi_system_table_t *sys_table_arg, struct screen_info *si)efi_call_early (free_pool, si); } -static efi_status_t reserve_kernel_base (efi_system_table_t *sys_table_arg, -unsigned long dram_base, +static efi_status_t reserve_kernel_base (unsigned long dram_base,unsigned long *reserve_addr,unsigned long *reserve_size) {
@@ -119,7 +118,7 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,* released to the OS after ExitBootServices(), the decompressor can * safely overwrite them. */ - status =efi_get_memory_map (sys_table_arg, &map); + status =efi_get_memory_map (&map);if (status !=EFI_SUCCESS ) {pr_efi_err ("reserve_kernel_base(): Unable to retrieve memory map.\n" );return status;
@@ -190,8 +189,7 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,return status; } -efi_status_t handle_kernel_image(efi_system_table_t *sys_table, - unsigned long *image_addr, +efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, unsigned long *reserve_size,
@@ -219,8 +217,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,*/ kernel_base +=TEXT_OFFSET -5 *PAGE_SIZE ; - status =reserve_kernel_base (sys_table, kernel_base, reserve_addr, - reserve_size); + status =reserve_kernel_base (kernel_base, reserve_addr, reserve_size);if (status !=EFI_SUCCESS ) {pr_efi_err ("Unable to allocate memory for uncompressed kernel.\n" );return status;
@@ -231,12 +228,11 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,* memory window. */ *image_size = image->image_size; - status =efi_relocate_kernel (sys_table, image_addr, *image_size, - *image_size, + status =efi_relocate_kernel (image_addr, *image_size, *image_size, kernel_base +MAX_UNCOMP_KERNEL_SIZE ,0 ,0 );if (status !=EFI_SUCCESS ) {pr_efi_err ("Failed to relocate kernel.\n" ); -efi_free (sys_table, *reserve_size, *reserve_addr); +efi_free (*reserve_size, *reserve_addr); *reserve_size =0 ;return status; }
@@ -248,9 +244,9 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,*/ if (*image_addr + *image_size > dram_base +ZIMAGE_OFFSET_LIMIT ) {pr_efi_err ("Failed to relocate kernel, no low memory available.\n" ); -efi_free (sys_table, *reserve_size, *reserve_addr); +efi_free (*reserve_size, *reserve_addr); *reserve_size =0 ; -efi_free (sys_table, *image_size, *image_addr); +efi_free (*image_size, *image_addr); *image_size =0 ;return EFI_LOAD_ERROR ; }
drivers/firmware/efi/libstub/arm64-stub.c +5 -7
@@ -21,7 +21,7 @@#include "efistub.h" -efi_status_t check_platform_features (efi_system_table_t *sys_table_arg) +efi_status_t check_platform_features (void ) {u64 tg;
@@ -40,8 +40,7 @@ efi_status_t check_platform_features(efi_system_table_t *sys_table_arg)return EFI_SUCCESS ; } -efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg, - unsigned long *image_addr, +efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, unsigned long *reserve_size,
@@ -56,8 +55,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) {if (!nokaslr ()) { - status =efi_get_random_bytes (sys_table_arg, -sizeof (phys_seed), + status =efi_get_random_bytes (sizeof (phys_seed), (u8 *)&phys_seed);if (status ==EFI_NOT_FOUND ) {pr_efi ("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n" );
@@ -108,7 +106,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,* locate the kernel at a randomized offset in physical memory. */ *reserve_size = kernel_memsize + offset; - status =efi_random_alloc (sys_table_arg, *reserve_size, + status =efi_random_alloc (*reserve_size,MIN_KIMG_ALIGN , reserve_addr, (u32 )phys_seed);
@@ -139,7 +137,7 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table_arg,if (status !=EFI_SUCCESS ) { *reserve_size = kernel_memsize +TEXT_OFFSET ; - status =efi_low_alloc (sys_table_arg, *reserve_size, + status =efi_low_alloc (*reserve_size,MIN_KIMG_ALIGN , reserve_addr);if (status !=EFI_SUCCESS ) {
drivers/firmware/efi/libstub/efi-stub-helper.c +33 -41
215 lines not on this page · raw message
drivers/firmware/efi/libstub/efistub.h +7 -10
@@ -40,10 +40,9 @@ extern __pure efi_system_table_t *efi_system_table(void);void efi_char16_printk (efi_char16_t *);void efi_char16_printk (efi_char16_t *); -unsigned long get_dram_base (efi_system_table_t *sys_table_arg); +unsigned long get_dram_base (void ); -efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, - void *handle, +efi_status_t allocate_new_fdt_and_exit_boot(void *handle, unsigned long *new_fdt_addr, unsigned long max_addr, u64 initrd_addr, u64 initrd_size,
@@ -51,22 +50,20 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,unsigned long fdt_addr, unsigned long fdt_size); -void *get_fdt (efi_system_table_t *sys_table,unsigned long *fdt_size); +void *get_fdt (unsigned long *fdt_size);void efi_get_virtmap (efi_memory_desc_t *memory_map,unsigned long map_size,unsigned long desc_size,efi_memory_desc_t *runtime_map,int *count); -efi_status_t efi_get_random_bytes (efi_system_table_t *sys_table, -unsigned long size,u8 *out); +efi_status_t efi_get_random_bytes (unsigned long size,u8 *out); -efi_status_t efi_random_alloc (efi_system_table_t *sys_table_arg, -unsigned long size,unsigned long align, +efi_status_t efi_random_alloc (unsigned long size,unsigned long align,unsigned long *addr,unsigned long random_seed); -efi_status_t check_platform_features (efi_system_table_t *sys_table_arg); +efi_status_t check_platform_features (void ); -void *get_efi_config_table (efi_system_table_t *sys_table,efi_guid_t guid); +void *get_efi_config_table (efi_guid_t guid);/* Helper macros for the usual case of using simple C variables: */ #ifndef fdt_setprop_inplace_var
drivers/firmware/efi/libstub/fdt.c +17 -20
@@ -16,7 +16,7 @@#define EFI_DT_ADDR_CELLS_DEFAULT 2#define EFI_DT_SIZE_CELLS_DEFAULT 2 -static void fdt_update_cell_size (efi_system_table_t *sys_table,void *fdt) +static void fdt_update_cell_size (void *fdt) {int offset;
@@ -27,8 +27,7 @@ static void fdt_update_cell_size(efi_system_table_t *sys_table, void *fdt)fdt_setprop_u32 (fdt, offset,"#size-cells" ,EFI_DT_SIZE_CELLS_DEFAULT ); } -static efi_status_t update_fdt (efi_system_table_t *sys_table,void *orig_fdt, -unsigned long orig_fdt_size, +static efi_status_t update_fdt (void *orig_fdt,unsigned long orig_fdt_size,void *fdt,int new_fdt_size,char *cmdline_ptr,u64 initrd_addr,u64 initrd_size) {
@@ -62,7 +61,7 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,* Any failure from the following function is * non-critical: */ -fdt_update_cell_size (sys_table, fdt); +fdt_update_cell_size (fdt); } }
@@ -111,7 +110,7 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,/* Add FDT entries for EFI runtime services in chosen node. */ node =fdt_subnode_offset (fdt,0 ,"chosen" ); - fdt_val64 =cpu_to_fdt64 ((u64 )(unsigned long )sys_table); + fdt_val64 =cpu_to_fdt64 ((u64 )(unsigned long )efi_system_table ()); status =fdt_setprop_var (fdt, node,"linux,uefi-system-table" , fdt_val64);if (status)
@@ -140,7 +139,7 @@ static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,if (IS_ENABLED (CONFIG_RANDOMIZE_BASE )) {efi_status_t efi_status; - efi_status =efi_get_random_bytes (sys_table,sizeof (fdt_val64), + efi_status =efi_get_random_bytes (sizeof (fdt_val64), (u8 *)&fdt_val64);if (efi_status ==EFI_SUCCESS ) { status =fdt_setprop_var (fdt, node,"kaslr-seed" , fdt_val64);
@@ -210,8 +209,7 @@ struct exit_boot_struct {void *new_fdt_addr; }; -static efi_status_t exit_boot_func (efi_system_table_t *sys_table_arg, -struct efi_boot_memmap *map, +static efi_status_t exit_boot_func (struct efi_boot_memmap *map,void *priv) {struct exit_boot_struct *p = priv;
@@ -244,8 +242,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,* with the final memory map in it. */ -efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, - void *handle, +efi_status_t allocate_new_fdt_and_exit_boot(void *handle, unsigned long *new_fdt_addr, unsigned long max_addr, u64 initrd_addr, u64 initrd_size,
@@ -275,7 +272,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,* subsequent allocations adding entries, since they could not affect * the number of EFI_MEMORY_RUNTIME regions. */ - status =efi_get_memory_map (sys_table, &map); + status =efi_get_memory_map (&map);if (status !=EFI_SUCCESS ) {pr_efi_err ("Unable to retrieve UEFI memory map.\n" );return status;
@@ -284,7 +281,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,pr_efi ("Exiting boot services and installing virtual address map...\n" ); map.map = &memory_map; - status =efi_high_alloc (sys_table,MAX_FDT_SIZE ,EFI_FDT_ALIGN , + status =efi_high_alloc (MAX_FDT_SIZE ,EFI_FDT_ALIGN , new_fdt_addr, max_addr);if (status !=EFI_SUCCESS ) {pr_efi_err ("Unable to allocate memory for new device tree.\n" );
@@ -295,11 +292,11 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,* Now that we have done our final memory allocation (and free) * we can get the memory map key needed for exit_boot_services(). */ - status =efi_get_memory_map (sys_table, &map); + status =efi_get_memory_map (&map);if (status !=EFI_SUCCESS ) goto fail_free_new_fdt; - status =update_fdt (sys_table, (void *)fdt_addr, fdt_size, + status =update_fdt ((void *)fdt_addr, fdt_size, (void *)*new_fdt_addr,MAX_FDT_SIZE , cmdline_ptr, initrd_addr, initrd_size);
@@ -313,7 +310,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, priv.runtime_entry_count = &runtime_entry_count; priv.new_fdt_addr = (void *)*new_fdt_addr; - status =efi_exit_boot_services (sys_table, handle, &map, &priv, exit_boot_func); + status =efi_exit_boot_services (handle, &map, &priv, exit_boot_func);if (status ==EFI_SUCCESS ) {efi_set_virtual_address_map_t *svam;
@@ -322,7 +319,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,return EFI_SUCCESS ;/* Install the new virtual address map */ - svam = sys_table->runtime->set_virtual_address_map; + svam =efi_system_table ()->runtime->set_virtual_address_map; status =svam (runtime_entry_count * desc_size, desc_size, desc_ver, runtime_map);
@@ -353,19 +350,19 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,pr_efi_err ("Exit boot services failed.\n" ); fail_free_new_fdt: -efi_free (sys_table,MAX_FDT_SIZE , *new_fdt_addr); +efi_free (MAX_FDT_SIZE , *new_fdt_addr); fail: - sys_table->boottime->free_pool (runtime_map); +efi_system_table ()->boottime->free_pool (runtime_map);return EFI_LOAD_ERROR ; } -void *get_fdt (efi_system_table_t *sys_table,unsigned long *fdt_size) +void *get_fdt (unsigned long *fdt_size) {void *fdt; - fdt =get_efi_config_table (sys_table,DEVICE_TREE_GUID ); + fdt =get_efi_config_table (DEVICE_TREE_GUID );if (!fdt)return NULL ;
drivers/firmware/efi/libstub/gop.c +4 -6
@@ -88,9 +88,8 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line,#define efi_gop_attr (table, attr, instance) \ (efi_table_attr(efi_graphics_output_protocol##table, attr, instance)) -static efi_status_t -setup_gop (efi_system_table_t *sys_table_arg,struct screen_info *si, -efi_guid_t *proto,unsigned long size,void **handles) +static efi_status_t setup_gop (struct screen_info *si,efi_guid_t *proto, +unsigned long size,void **handles) {efi_graphics_output_protocol_t *gop, *first_gop;u16 width, height;
@@ -185,8 +184,7 @@ setup_gop(efi_system_table_t *sys_table_arg, struct screen_info *si,/* * See if we have Graphics Output Protocol */ -efi_status_t efi_setup_gop (efi_system_table_t *sys_table_arg, -struct screen_info *si,efi_guid_t *proto, +efi_status_t efi_setup_gop (struct screen_info *si,efi_guid_t *proto,unsigned long size) {efi_status_t status;
@@ -203,7 +201,7 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,if (status !=EFI_SUCCESS ) goto free_handle; - status =setup_gop (sys_table_arg, si, proto, size, gop_handle); + status =setup_gop (si, proto, size, gop_handle); free_handle:efi_call_early (free_pool, gop_handle);
drivers/firmware/efi/libstub/random.c +4 -6
@@ -26,8 +26,7 @@ union efi_rng_protocol { } mixed_mode; }; -efi_status_t efi_get_random_bytes (efi_system_table_t *sys_table_arg, -unsigned long size,u8 *out) +efi_status_t efi_get_random_bytes (unsigned long size,u8 *out) {efi_guid_t rng_proto =EFI_RNG_PROTOCOL_GUID ;efi_status_t status;
@@ -79,8 +78,7 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,*/ #define MD_NUM_SLOTS (md) ((md)->virt_addr) -efi_status_t efi_random_alloc (efi_system_table_t *sys_table_arg, -unsigned long size, +efi_status_t efi_random_alloc (unsigned long size,unsigned long align,unsigned long *addr,unsigned long random_seed)
@@ -99,7 +97,7 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg, map.key_ptr =NULL ; map.buff_size = &buff_size; - status =efi_get_memory_map (sys_table_arg, &map); + status =efi_get_memory_map (&map);if (status !=EFI_SUCCESS )return status;
@@ -155,7 +153,7 @@ efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,return status; } -efi_status_t efi_random_get_seed (efi_system_table_t *sys_table_arg) +efi_status_t efi_random_get_seed (void ) {efi_guid_t rng_proto =EFI_RNG_PROTOCOL_GUID ;efi_guid_t rng_algo_raw =EFI_RNG_ALGORITHM_RAW ;
drivers/firmware/efi/libstub/secureboot.c +1 -1
@@ -32,7 +32,7 @@ static const efi_char16_t shim_MokSBState_name[] = L"MokSBState";* Please keep the logic in sync with * arch/x86/xen/efi.c:xen_efi_get_secureboot(). */ -enum efi_secureboot_mode efi_get_secureboot (efi_system_table_t *sys_table_arg) +enum efi_secureboot_mode efi_get_secureboot (void ) {u32 attr;u8 secboot, setupmode, moksbstate;
drivers/firmware/efi/libstub/tpm.c +2 -3
@@ -57,7 +57,7 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)#endif -void efi_retrieve_tpm2_eventlog (efi_system_table_t *sys_table_arg) +void efi_retrieve_tpm2_eventlog (void ) {efi_guid_t tcg2_guid =EFI_TCG2_PROTOCOL_GUID ;efi_guid_t linux_eventlog_guid =LINUX_EFI_TPM_EVENT_LOG_GUID ;
@@ -139,8 +139,7 @@ void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)* Figure out whether any events have already been logged to the * final events structure, and if so how much space they take up */ - final_events_table =get_efi_config_table (sys_table_arg, -LINUX_EFI_TPM_FINAL_LOG_GUID ); + final_events_table =get_efi_config_table (LINUX_EFI_TPM_FINAL_LOG_GUID );if (final_events_table && final_events_table->nr_events) {struct tcg_pcr_event2_head *header;int offset;
include/linux/efi.h +16 -27
99 lines not on this page · raw message
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 16/21 efi/libstub: drop protocol argument from efi_call_proto() macro
In reply to Ard BiesheuvelAfter refactoring the mixed mode support code, efi_call_proto() no longer uses its protocol argument in any of its implementation, so let's remove it altogether.
--- arch/arm/include/asm/efi.h | 3 +-- arch/arm64/include/asm/efi.h | 3 +-- arch/x86/boot/compressed/eboot.c | 23 ++++++++------------ arch/x86/include/asm/efi.h | 6 ++--- drivers/firmware/efi/libstub/efi-stub-helper.c | 22 ++++++++----------- drivers/firmware/efi/libstub/random.c | 8 +++---- drivers/firmware/efi/libstub/tpm.c | 11 +++++----- 7 files changed, 32 insertions(+), 44 deletions(-)
arch/arm/include/asm/efi.h +1 -2
@@ -57,8 +57,7 @@ void efi_virtmap_unload(void);#define efi_table_attr (table, attr, instance) \ instance->attr -#define efi_call_proto (protocol, f, instance, ...) \ - instance->f(instance, ##__VA_ARGS__) +#define efi_call_proto (inst, func, ...) inst->func(inst, ##__VA_ARGS__)struct screen_info *alloc_screen_info (void );void free_screen_info (struct screen_info *si);
arch/arm64/include/asm/efi.h +1 -2
@@ -100,8 +100,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,#define efi_table_attr (table, attr, instance) \ instance->attr -#define efi_call_proto (protocol, f, instance, ...) \ - instance->f(instance, ##__VA_ARGS__) +#define efi_call_proto (inst, func, ...) inst->func(inst, ##__VA_ARGS__) #define alloc_screen_info(x...) &screen_info
arch/x86/boot/compressed/eboot.c +9 -14
@@ -76,27 +76,24 @@ preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) rom->pcilen = pci->romsize; *__rom = rom; - status =efi_call_proto (efi_pci_io_protocol, pci.read, pci, - EfiPciIoWidthUint16,PCI_VENDOR_ID ,1 , - &rom->vendor); + status =efi_call_proto (pci, pci.read, EfiPciIoWidthUint16, +PCI_VENDOR_ID ,1 , &rom->vendor);if (status !=EFI_SUCCESS ) {efi_printk ("Failed to read rom->vendor\n" ); goto free_struct; } - status =efi_call_proto (efi_pci_io_protocol, pci.read, pci, - EfiPciIoWidthUint16,PCI_DEVICE_ID ,1 , - &rom->devid); + status =efi_call_proto (pci, pci.read, EfiPciIoWidthUint16, +PCI_DEVICE_ID ,1 , &rom->devid);if (status !=EFI_SUCCESS ) {efi_printk ("Failed to read rom->devid\n" ); goto free_struct; } - status =efi_call_proto (efi_pci_io_protocol, get_location, pci, - &rom->segment, &rom->bus, &rom->device, - &rom->function); + status =efi_call_proto (pci, get_location, &rom->segment, &rom->bus, + &rom->device, &rom->function);if (status !=EFI_SUCCESS ) goto free_struct;
@@ -198,7 +195,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)return ; } -efi_call_proto (apple_properties_protocol, get_all, p,NULL , &size); +efi_call_proto (p, get_all,NULL , &size);if (!size)return ;
@@ -211,8 +208,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)return ; } - status =efi_call_proto (apple_properties_protocol, get_all, p, - new->data, &size); + status =efi_call_proto (p, get_all, new->data, &size);if (status ==EFI_BUFFER_TOO_SMALL )efi_call_early (free_pool, new);
@@ -287,8 +283,7 @@ setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size) pciio =NULL ;efi_call_early (handle_protocol, handle, &pciio_proto, &pciio); - status =efi_call_proto (efi_uga_draw_protocol, get_mode, uga, - &w, &h, &depth, &refresh); + status =efi_call_proto (uga, get_mode, &w, &h, &depth, &refresh);if (status ==EFI_SUCCESS && (!first_uga || pciio)) { width = w; height = h;
arch/x86/include/asm/efi.h +3 -3
@@ -236,10 +236,10 @@ static inline bool efi_is_native(void) __ret; \ }) -#define efi_call_proto (protocol, f, instance, ...) \ +#define efi_call_proto (inst, func, ...) \ (efi_is_native() \ - ? instance->f(instance, ##__VA_ARGS__) \ - : efi64_thunk(instance->mixed_mode.f, instance, ##__VA_ARGS__)) + ? inst->func(inst, ##__VA_ARGS__) \ + : efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__))#define efi_call_early (f, ...) \ (efi_is_native() \
drivers/firmware/efi/libstub/efi-stub-helper.c +9 -13
@@ -370,8 +370,8 @@ static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,efi_guid_t info_guid =EFI_FILE_INFO_ID ;unsigned long info_sz; - status =efi_call_proto (efi_file_handle, open, fh, &h, filename_16, -EFI_FILE_MODE_READ , (u64 )0 ); + status =efi_call_proto (fh, open, &h, filename_16,EFI_FILE_MODE_READ , + (u64 )0 );if (status !=EFI_SUCCESS ) {efi_printk ("Failed to open file: " );efi_char16_printk (filename_16);
@@ -382,8 +382,7 @@ static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16, *handle = h; info_sz =0 ; - status =efi_call_proto (efi_file_handle, get_info, h, &info_guid, - &info_sz,NULL ); + status =efi_call_proto (h, get_info, &info_guid, &info_sz,NULL );if (status !=EFI_BUFFER_TOO_SMALL ) {efi_printk ("Failed to get file info size\n" );return status;
@@ -397,8 +396,7 @@ static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,return status; } - status =efi_call_proto (efi_file_handle, get_info, h, &info_guid, - &info_sz, info); + status =efi_call_proto (h, get_info, &info_guid, &info_sz, info);if (status ==EFI_BUFFER_TOO_SMALL ) {efi_call_early (free_pool, info); goto grow;
@@ -416,12 +414,12 @@ static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,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); +return efi_call_proto (handle, read, size, addr); }static efi_status_t efi_file_close (efi_file_handle_t *handle) { -return efi_call_proto (efi_file_handle, close, handle); +return efi_call_proto (handle, close); } static efi_status_t efi_open_volume(efi_loaded_image_t *image,
@@ -440,7 +438,7 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,return status; } - status =efi_call_proto (efi_file_io_interface, open_volume, io, &fh); + status =efi_call_proto (io, open_volume, &fh);if (status !=EFI_SUCCESS )efi_printk ("Failed to open volume\n" );else
@@ -969,9 +967,7 @@ void *get_efi_config_table(efi_guid_t guid)void efi_char16_printk (efi_char16_t *str) { -efi_call_proto (efi_simple_text_output_protocol, - output_string, -efi_table_attr (efi_system_table, con_out, +efi_call_proto (efi_table_attr (efi_system_table, con_out,efi_system_table ()), - str); + output_string, str); }
drivers/firmware/efi/libstub/random.c +4 -4
@@ -37,7 +37,7 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)if (status !=EFI_SUCCESS )return status; -return efi_call_proto (efi_rng_protocol, get_rng, rng,NULL , size, out); +return efi_call_proto (rng, get_rng,NULL , size, out); }/*
@@ -173,7 +173,7 @@ efi_status_t efi_random_get_seed(void)if (status !=EFI_SUCCESS )return status; - status =efi_call_proto (efi_rng_protocol, get_rng, rng, &rng_algo_raw, + status =efi_call_proto (rng, get_rng, &rng_algo_raw,EFI_RANDOM_SEED_SIZE , seed->bits);if (status ==EFI_UNSUPPORTED )
@@ -181,8 +181,8 @@ efi_status_t efi_random_get_seed(void)* Use whatever algorithm we have available if the raw algorithm * is not implemented. */ - status =efi_call_proto (efi_rng_protocol, get_rng, rng,NULL , -EFI_RANDOM_SEED_SIZE , seed->bits); + status =efi_call_proto (rng, get_rng,NULL , +EFI_RANDOM_SEED_SIZE , seed->bits);if (status !=EFI_SUCCESS ) goto err_freepool;
drivers/firmware/efi/libstub/tpm.c +5 -6
@@ -77,15 +77,14 @@ void efi_retrieve_tpm2_eventlog(void)if (status !=EFI_SUCCESS )return ; - status =efi_call_proto (efi_tcg2_protocol, get_event_log, - tcg2_protocol, version, &log_location, - &log_last_entry, &truncated); + status =efi_call_proto (tcg2_protocol, get_event_log, version, + &log_location, &log_last_entry, &truncated);if (status !=EFI_SUCCESS || !log_location) { version =EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 ; - status =efi_call_proto (efi_tcg2_protocol, get_event_log, - tcg2_protocol, version, &log_location, - &log_last_entry, &truncated); + status =efi_call_proto (tcg2_protocol, get_event_log, version, + &log_location, &log_last_entry, + &truncated);if (status !=EFI_SUCCESS || !log_location)return ;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 17/21 efi/libstub: drop 'table' argument from efi_table_attr() macro
In reply to Ard BiesheuvelNone of the definitions of the efi_table_attr() still refer to their 'table' argument so let's get rid of it entirely.
--- arch/arm/include/asm/efi.h | 3 +-- arch/arm64/include/asm/efi.h | 3 +-- arch/x86/boot/compressed/eboot.c | 8 +++---- arch/x86/include/asm/efi.h | 25 +++++++------------- drivers/firmware/efi/libstub/efi-stub-helper.c | 13 ++++------ drivers/firmware/efi/libstub/gop.c | 9 +++---- 6 files changed, 23 insertions(+), 38 deletions(-)
arch/arm/include/asm/efi.h +1 -2
@@ -54,8 +54,7 @@ void efi_virtmap_unload(void);#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__)#define efi_is_native () (true) -#define efi_table_attr (table, attr, instance) \ - instance->attr +#define efi_table_attr (inst, attr) (inst->attr)#define efi_call_proto (inst, func, ...) inst->func(inst, ##__VA_ARGS__)
arch/arm64/include/asm/efi.h +1 -2
@@ -97,8 +97,7 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__)#define efi_is_native () (true) -#define efi_table_attr (table, attr, instance) \ - instance->attr +#define efi_table_attr (inst, attr) (inst->attr)#define efi_call_proto (inst, func, ...) inst->func(inst, ##__VA_ARGS__)
arch/x86/boot/compressed/eboot.c +4 -4
@@ -54,8 +54,8 @@ 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 * MiB so we reject any ROMs over 16 MiB in size to catch this. */ - romimage =efi_table_attr (efi_pci_io_protocol, romimage, pci); - romsize =efi_table_attr (efi_pci_io_protocol, romsize, pci); + romimage =efi_table_attr (pci, romimage); + romsize =efi_table_attr (pci, romsize);if (!romimage || !romsize || romsize >SZ_16M )return EFI_INVALID_PARAMETER ;
@@ -190,7 +190,7 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)if (status !=EFI_SUCCESS )return ; -if (efi_table_attr (apple_properties_protocol, version, p) !=0x10000 ) { +if (efi_table_attr (p, version) !=0x10000 ) {efi_printk ("Unsupported properties proto version\n" );return ; }
@@ -233,7 +233,7 @@ static const efi_char16_t apple[] = L"Apple";static void setup_quirks (struct boot_params *boot_params) {efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long ) -efi_table_attr (efi_system_table, fw_vendor, sys_table); +efi_table_attr (efi_system_table (), fw_vendor);if (!memcmp (fw_vendor, apple,sizeof (apple))) {if (IS_ENABLED (CONFIG_APPLE_PROPERTIES ))
arch/x86/include/asm/efi.h +9 -16
@@ -225,16 +225,11 @@ static inline bool efi_is_native(void) __builtin_types_compatible_p(u32, __typeof__(attr)), \ (unsigned long)(attr), (attr)) -#define efi_table_attr (table, attr, instance) ({ \ - __typeof__(instance->attr) __ret; \ - if (efi_is_native()) { \ - __ret = instance->attr; \ - } else { \ - __ret = (__typeof__(__ret)) \ - efi_mixed_mode_cast(instance->mixed_mode.attr); \ - } \ - __ret; \ -}) +#define efi_table_attr (inst, attr) \ + (efi_is_native() \ + ? inst->attr \ + : (__typeof__(inst->attr)) \ + efi_mixed_mode_cast(inst->mixed_mode.attr))#define efi_call_proto (inst, func, ...) \ (efi_is_native() \
@@ -244,16 +239,14 @@ static inline bool efi_is_native(void)#define efi_call_early (f, ...) \ (efi_is_native() \ ? efi_system_table()->boottime->f(__VA_ARGS__) \ - : efi64_thunk(efi_table_attr(efi_boot_services, \ - boottime, efi_system_table())->mixed_mode.f, \ - __VA_ARGS__)) + : efi64_thunk(efi_table_attr(efi_system_table(), \ + boottime)->mixed_mode.f, __VA_ARGS__))#define efi_call_runtime (f, ...) \ (efi_is_native() \ ? efi_system_table()->runtime->f(__VA_ARGS__) \ - : efi64_thunk(efi_table_attr(efi_runtime_services, \ - runtime, efi_system_table())->mixed_mode.f, \ - __VA_ARGS__)) + : efi64_thunk(efi_table_attr(efi_system_table(), \ + runtime)->mixed_mode.f, __VA_ARGS__))extern bool efi_reboot_required (void );extern bool efi_is_table_address (unsigned long phys_addr);
drivers/firmware/efi/libstub/efi-stub-helper.c +5 -8
@@ -429,7 +429,7 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,efi_file_handle_t *fh;efi_guid_t fs_proto =EFI_FILE_SYSTEM_GUID ;efi_status_t status; -void *handle =efi_table_attr (efi_loaded_image, device_handle, image); +void *handle =efi_table_attr (image, device_handle); status =efi_call_early (handle_protocol, handle, &fs_proto, (void **)&io);
@@ -947,17 +947,15 @@ efi_status_t efi_exit_boot_services(void *handle,void *get_efi_config_table (efi_guid_t guid) { -unsigned long tables =efi_table_attr (efi_system_table, tables, -efi_system_table ()); -int nr_tables =efi_table_attr (efi_system_table, nr_tables, -efi_system_table ()); +unsigned long tables =efi_table_attr (efi_system_table (), tables); +int nr_tables =efi_table_attr (efi_system_table (), nr_tables);int i;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); +return efi_table_attr (t, table); tables +=efi_is_native () ?sizeof (efi_config_table_t) :sizeof (efi_config_table_32_t);
@@ -967,7 +965,6 @@ void *get_efi_config_table(efi_guid_t guid)void efi_char16_printk (efi_char16_t *str) { -efi_call_proto (efi_table_attr (efi_system_table, con_out, -efi_system_table ()), +efi_call_proto (efi_table_attr (efi_system_table (), con_out), output_string, str); }
drivers/firmware/efi/libstub/gop.c +3 -6
@@ -85,9 +85,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, } } -#define efi_gop_attr (table, attr, instance) \ - (efi_table_attr(efi_graphics_output_protocol##table, attr, instance)) -static efi_status_t setup_gop (struct screen_info *si,efi_guid_t *proto,unsigned long size,void **handles) {
@@ -123,9 +120,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,if (status ==EFI_SUCCESS ) conout_found = true; - mode = (void *)(unsigned long)efi_gop_attr(, mode, gop); - info = (void *)(unsigned long )efi_gop_attr (_mode, info, mode); - current_fb_base =efi_gop_attr (_mode, frame_buffer_base, mode); + mode =efi_table_attr (gop, mode); + info =efi_table_attr (mode, info); + current_fb_base =efi_table_attr (mode, frame_buffer_base);if ((!first_gop || conout_found) && info->pixel_format !=PIXEL_BLT_ONLY ) {
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 18/21 efi/libstub: use 'func' not 'f' as macro parameter
In reply to Ard BiesheuvelUse 'func' as the macro parameter name for the efi_call() macros which is less likely to collide and cause weird build errors.
--- arch/arm64/include/asm/efi.h | 4 ++-- arch/x86/include/asm/efi.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-)
arch/arm64/include/asm/efi.h +2 -2
@@ -93,8 +93,8 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,return (image_addr & ~(SZ_1G -1UL )) + (1UL << (VA_BITS_MIN -1 )); } -#define efi_call_early (f, ...) efi_system_table()->boottime->f(__VA_ARGS__) -#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__) +#define efi_call_early (func, ...) efi_system_table()->boottime->func(__VA_ARGS__) +#define efi_call_runtime (func, ...) efi_system_table()->runtime->func(__VA_ARGS__)#define efi_is_native () (true)#define efi_table_attr (inst, attr) (inst->attr)
arch/x86/include/asm/efi.h +6 -6
@@ -236,17 +236,17 @@ static inline bool efi_is_native(void) ? inst->func(inst, ##__VA_ARGS__) \ : efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__)) -#define efi_call_early (f, ...) \ +#define efi_call_early (func, ...) \ (efi_is_native() \ - ? efi_system_table()->boottime->f(__VA_ARGS__) \ + ? efi_system_table()->boottime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - boottime)->mixed_mode.f, __VA_ARGS__)) + boottime)->mixed_mode.func, __VA_ARGS__)) -#define efi_call_runtime (f, ...) \ +#define efi_call_runtime (func, ...) \ (efi_is_native() \ - ? efi_system_table()->runtime->f(__VA_ARGS__) \ + ? efi_system_table()->runtime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - runtime)->mixed_mode.f, __VA_ARGS__)) + runtime)->mixed_mode.func, __VA_ARGS__))extern bool efi_reboot_required (void );extern bool efi_is_table_address (unsigned long phys_addr);
Signature · 1 line
2.17.1
Re: [PATCH v2 18/21] efi/libstub: use 'func' not 'f' as macro parameter
Quoted 3 lines · Ard Biesheuvel
Use 'func' as the macro parameter name for the
efi_call()macros which is less likely to collide and cause weird build errors.
For my education, what are the possible collisions/build errors that might happen?
Thanks
Quoted 52 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 4 ++-- arch/x86/include/asm/efi.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-)arch/arm64/include/asm/efi.h +2
-2@@ -93,8 +93,8 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,return (image_addr & ~(SZ_1G -1UL )) + (1UL << (VA_BITS_MIN -1 )); } -#define efi_call_early (f, ...) efi_system_table()->boottime->f(__VA_ARGS__) -#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__) +#define efi_call_early (func, ...) efi_system_table()->boottime->func(__VA_ARGS__) +#define efi_call_runtime (func, ...) efi_system_table()->runtime->func(__VA_ARGS__)#define efi_is_native () (true)#define efi_table_attr (inst, attr) (inst->attr)arch/x86/include/asm/efi.h +6
-6@@ -236,17 +236,17 @@ static inline bool efi_is_native(void) ? inst->func(inst, ##__VA_ARGS__) \ : efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__)) -#define efi_call_early (f, ...) \ +#define efi_call_early (func, ...) \ (efi_is_native() \ - ? efi_system_table()->boottime->f(__VA_ARGS__) \ + ? efi_system_table()->boottime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - boottime)->mixed_mode.f, __VA_ARGS__)) + boottime)->mixed_mode.func, __VA_ARGS__)) -#define efi_call_runtime (f, ...) \ +#define efi_call_runtime (func, ...) \ (efi_is_native() \ - ? efi_system_table()->runtime->f(__VA_ARGS__) \ + ? efi_system_table()->runtime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - runtime)->mixed_mode.f, __VA_ARGS__)) + runtime)->mixed_mode.func, __VA_ARGS__))extern bool efi_reboot_required (void );extern bool efi_is_table_address (unsigned long phys_addr);Signature · 1 line
2.17.1
Re: [PATCH v2 18/21] efi/libstub: use 'func' not 'f' as macro parameter
Quoted 8 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Use 'func' as the macro parameter name for the
efi_call()macros which is less likely to collide and cause weird build errors.For my education, what are the possible collisions/build errors that might happen?
I was concerned about variables called 'f' being passed as one of the arguments, but now that I think of it, I'm not sure how that could break.
In any case, I'd like to keep this patch since it also increases legibility.
Quoted 52 lines
Quoted 52 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 4 ++-- arch/x86/include/asm/efi.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-)arch/arm64/include/asm/efi.h +2
-2@@ -93,8 +93,8 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,return (image_addr & ~(SZ_1G -1UL )) + (1UL << (VA_BITS_MIN -1 )); } -#define efi_call_early (f, ...) efi_system_table()->boottime->f(__VA_ARGS__) -#define efi_call_runtime (f, ...) efi_system_table()->runtime->f(__VA_ARGS__) +#define efi_call_early (func, ...) efi_system_table()->boottime->func(__VA_ARGS__) +#define efi_call_runtime (func, ...) efi_system_table()->runtime->func(__VA_ARGS__)#define efi_is_native () (true)#define efi_table_attr (inst, attr) (inst->attr)arch/x86/include/asm/efi.h +6
-7@@ -236,17 +236,17 @@ static inline bool efi_is_native(void) ? inst->func(inst, ##__VA_ARGS__) \ : efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__)) -#define efi_call_early (f, ...) \ +#define efi_call_early (func, ...) \ (efi_is_native() \ - ? efi_system_table()->boottime->f(__VA_ARGS__) \ + ? efi_system_table()->boottime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - boottime)->mixed_mode.f, __VA_ARGS__)) + boottime)->mixed_mode.func, __VA_ARGS__)) -#define efi_call_runtime (f, ...) \ +#define efi_call_runtime (func, ...) \ (efi_is_native() \ - ? efi_system_table()->runtime->f(__VA_ARGS__) \ + ? efi_system_table()->runtime->func(__VA_ARGS__) \ : efi64_thunk(efi_table_attr(efi_system_table(), \ - runtime)->mixed_mode.f, __VA_ARGS__)) + runtime)->mixed_mode.func, __VA_ARGS__))extern bool efi_reboot_required (void );extern bool efi_is_table_address (unsigned long phys_addr); --2.17.1
Re: [PATCH v2 18/21] efi/libstub: use 'func' not 'f' as macro parameter
Quoted 7 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Use 'func' as the macro parameter name for the
efi_call()macros which is less likely to collide and cause weird build errors.
Quoted 9 lines
Quoted 2 lines
For my education, what are the possible collisions/build errors that might happen?
I was concerned about variables called 'f' being passed as one of the arguments, but now that I think of it, I'm not sure how that could break.
In any case, I'd like to keep this patch since it also increases legibility.
No objections to the patch, I just wanted to check if I was missing something. Probably update the commit message though.
Ard Biesheuvel
maintainerPATCH v2 19/21 efi/libstub: tidy up types and names of global cmdline variables
In reply to Ard BiesheuvelDrop leading underscores and use bool not int for true/false variables set on the command line.
--- drivers/firmware/efi/libstub/efi-stub-helper.c | 34 ++++++++++---------- drivers/firmware/efi/libstub/efistub.h | 6 ++-- 2 files changed, 20 insertions(+), 20 deletions(-)
drivers/firmware/efi/libstub/efi-stub-helper.c +17 -17
@@ -27,24 +27,24 @@*/ #define EFI_READ_CHUNK_SIZE (1024 * 1024) -static unsigned long __chunk_size =EFI_READ_CHUNK_SIZE ; +static unsigned long efi_chunk_size =EFI_READ_CHUNK_SIZE ; -static int __section(.data) __nokaslr; -static int __section(.data) __quiet; -static int __section(.data) __novamap; +static bool __section(.data) efi_nokaslr; +static bool __section(.data) efi_quiet; +static bool __section(.data) efi_novamap; static bool __section(.data) efi_nosoftreserve; -int __pure nokaslr(void) +bool __pure nokaslr(void) { -return __nokaslr; +return efi_nokaslr; } -int __pure is_quiet (void ) +bool __pure is_quiet (void ) { -return __quiet; +return efi_quiet; } -int __pure novamap (void ) +bool __pure novamap (void ) { -return __novamap; +return efi_novamap; }bool __pure __efi_soft_reserve_enabled (void ) {
@@ -461,11 +461,11 @@ efi_status_t efi_parse_options(char const *cmdline) str =strstr (cmdline,"nokaslr" );if (str == cmdline || (str && str > cmdline && *(str -1 ) ==' ' )) - __nokaslr =1 ; + efi_nokaslr = true; str =strstr (cmdline,"quiet" );if (str == cmdline || (str && str > cmdline && *(str -1 ) ==' ' )) - __quiet =1 ; + efi_quiet = true;/* * If no EFI parameters were specified on the cmdline we've got
@@ -485,18 +485,18 @@ efi_status_t efi_parse_options(char const *cmdline)while (*str && *str !=' ' ) {if (!strncmp (str,"nochunk" ,7 )) { str +=strlen ("nochunk" ); - __chunk_size =-1UL ; + efi_chunk_size =-1UL ; }if (!strncmp (str,"novamap" ,7 )) { str +=strlen ("novamap" ); - __novamap =1 ; + efi_novamap = true; }if (IS_ENABLED (CONFIG_EFI_SOFT_RESERVE ) && !strncmp (str,"nosoftreserve" ,7 )) { str +=strlen ("nosoftreserve" ); - efi_nosoftreserve =1 ; + efi_nosoftreserve = true; }/* Group words together, delimited by "," */
@@ -661,8 +661,8 @@ efi_status_t handle_cmdline_files(efi_loaded_image_t *image,while (size) {unsigned long chunksize; -if (IS_ENABLED (CONFIG_X86 ) && size > __chunk_size) - chunksize = __chunk_size; +if (IS_ENABLED (CONFIG_X86 ) && size > efi_chunk_size) + chunksize = efi_chunk_size;else chunksize = size;
drivers/firmware/efi/libstub/efistub.h +3 -3
@@ -25,9 +25,9 @@#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE#endif -extern int __pure nokaslr (void ); -extern int __pure is_quiet (void ); -extern int __pure novamap (void ); +extern bool __pure nokaslr (void ); +extern bool __pure is_quiet (void ); +extern bool __pure novamap (void );extern __pure efi_system_table_t *efi_system_table (void );
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 20/21 efi/libstub: import type definitions for creating and signalling events
In reply to Ard BiesheuvelWe will use the EFI event handling infrastructure in a future patch to register a notification function that executes at the very end of ExitBootServices() to disable DMA on all PCI bridges in the system.
So import the missing macros and typedefs from the UEFI spec.
--- include/linux/efi.h | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
include/linux/efi.h +21 -2
@@ -270,6 +270,23 @@ typedef struct {u32 create_event_ex; }__packed efi_boot_services_32_t; +typedef unsigned long efi_tpl_t ; + +#define TPL_APPLICATION 4 +#define TPL_CALLBACK 8 +#define TPL_NOTIFY 16 +#define TPL_HIGH_LEVEL 31 + +typedef void *efi_event_t ; +typedef void (__efiapi *efi_event_notify_t)(efi_event_t, void *); + +#define EVT_TIMER 0x80000000 +#define EVT_RUNTIME 0x40000000 +#define EVT_NOTIFY_WAIT 0x00000100 +#define EVT_NOTIFY_SIGNAL 0x00000200 +#define EVT_SIGNAL_EXIT_BOOT_SERVICES 0x00000201 +#define EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE 0x60000202 +/* * EFI Boot Services table */
@@ -288,10 +305,12 @@ typedef union { efi_status_t (__efiapi *allocate_pool)(int, unsigned long, void **); efi_status_t (__efiapi *free_pool)(void *); -void *create_event; + efi_status_t (__efiapi *create_event)(u32 type, efi_tpl_t, + efi_event_notify_t, + void *, efi_event_t *);void *set_timer;void *wait_for_event; -void *signal_event; +efi_status_t (__efiapi *signal_event)(efi_event_t);void *close_event;void *check_event;void *install_protocol_interface;
Signature · 1 line
2.17.1
Ard Biesheuvel
maintainerPATCH v2 21/21 efi: Allow disabling PCI busmastering on bridges during boot
In reply to Ard BiesheuvelFrom: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of ExitBootServices() and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration when ExitBootServices() is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.
If CONFIG_EFI_DISABLE_PCI_DMA is enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges before ExitBootServices() completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.
This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
--- Documentation/admin-guide/kernel-parameters.txt | 4 + arch/x86/boot/compressed/eboot.c | 2 + drivers/firmware/efi/Kconfig | 22 ++++ drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/arm-stub.c | 1 + drivers/firmware/efi/libstub/efi-stub-helper.c | 17 +++ drivers/firmware/efi/libstub/efistub.h | 1 + drivers/firmware/efi/libstub/pci.c | 116 ++++++++++++++++++++ include/linux/efi.h | 2 + 9 files changed, 166 insertions(+), 1 deletion(-)
Documentation/admin-guide/kernel-parameters.txt +4 -0
@@ -1180,6 +1180,10 @@ claim. Specify efi=nosoftreserve to disable this reservation and treat the memory by its base type (i.e. EFI_CONVENTIONAL_MEMORY / "System RAM"). + disable_pci_dma: Disable the busmaster bit on all + PCI bridges while in the EFI boot stub + no_disable_pci_dma: Leave the busmaster bit set on all + PCI bridges while in the EFI boot stub efi_no_storage_paranoia [EFI; X86] Using this parameter you can use more than 50% of
arch/x86/boot/compressed/eboot.c +2 -0
@@ -126,6 +126,8 @@ static void setup_efi_pci(struct boot_params *params)efi_handle_t h;int i; +efi_pci_disable_bridge_busmaster (); + status =efi_call_early (locate_handle,EFI_LOCATE_BY_PROTOCOL , &pci_proto,NULL , &size, pci_handle);
drivers/firmware/efi/Kconfig +22 -0
@@ -215,6 +215,28 @@ config EFI_RCI2_TABLE Say Y here for Dell EMC PowerEdge systems. +config EFI_DISABLE_PCI_DMA + bool "Clear Busmaster bit on PCI bridges during ExitBootServices()" + help + Disable the busmaster bit in the control register on all PCI bridges + while calling ExitBootServices() and passing control to the runtime + kernel. System firmware may configure the IOMMU to prevent malicious + PCI devices from being able to attack the OS via DMA. However, since + firmware can't guarantee that the OS is IOMMU-aware, it will tear + down IOMMU configuration when ExitBootServices() is called. This + leaves a window between where a hostile device could still cause + damage before Linux configures the IOMMU again. + + If you say Y here, the EFI stub will clear the busmaster bit on all + PCI bridges before ExitBootServices() completes. This will prevent + any malicious PCI devices from being able to perform DMA until the + kernel reenables busmastering after configuring the IOMMU. + + This option will cause failures with some poorly behaved hardware + and should not be enabled without testing. The kernel commandline + options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be + used to override this option. + endmenu config UEFI_CPER
drivers/firmware/efi/libstub/Makefile +1 -1
@@ -39,7 +39,7 @@ OBJECT_FILES_NON_STANDARD := y KCOV_INSTRUMENT := n lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ - random.o + random.o pci.o # include the stub's generic dependencies from lib/ when building for ARM/arm64 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
drivers/firmware/efi/libstub/arm-stub.c +1 -0
@@ -257,6 +257,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg, }install_memreserve_table (); +efi_pci_disable_bridge_busmaster (); new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(handle,
drivers/firmware/efi/libstub/efi-stub-helper.c +17 -0
@@ -33,6 +33,8 @@ static bool __section(.data) efi_nokaslr; static bool __section(.data) efi_quiet; static bool __section(.data) efi_novamap; static bool __section(.data) efi_nosoftreserve; +static bool __section(.data) efi_disable_pci_dma = +IS_ENABLED (CONFIG_EFI_DISABLE_PCI_DMA ); bool __pure nokaslr(void) {
@@ -51,6 +53,11 @@ bool __pure __efi_soft_reserve_enabled(void)return !efi_nosoftreserve; } +bool __pure disable_pci_dma (void ) +{ +return efi_disable_pci_dma; +} +#define EFI_MMAP_NR_SLACK_SLOTS 8struct file_info {
@@ -499,6 +506,16 @@ efi_status_t efi_parse_options(char const *cmdline) efi_nosoftreserve = true; } +if (!strncmp (str,"disable_pci_dma" ,15 )) { + str +=strlen ("disable_pci_dma" ); + efi_disable_pci_dma = true; + } + +if (!strncmp (str,"no_disable_pci_dma" ,18 )) { + str +=strlen ("no_disable_pci_dma" ); + efi_disable_pci_dma = false; + } +/* Group words together, delimited by "," */ while (*str && *str !=' ' && *str !=',' ) str++;
drivers/firmware/efi/libstub/efistub.h +1 -0
@@ -28,6 +28,7 @@extern bool __pure nokaslr (void );extern bool __pure is_quiet (void );extern bool __pure novamap (void ); +extern bool __pure disable_pci_dma (void );extern __pure efi_system_table_t *efi_system_table (void );
drivers/firmware/efi/libstub/pci.c new file +116 -0
116 lines not on this page · raw message
include/linux/efi.h +2 -0
@@ -1786,4 +1786,6 @@ struct linux_efi_memreserve {#define EFI_MEMRESERVE_COUNT (size) (((size) - sizeof(struct linux_efi_memreserve)) \ / sizeof(((struct linux_efi_memreserve *)0)->entry[0])) +void efi_pci_disable_bridge_busmaster (void ); +#endif /* _LINUX_EFI_H */
Signature · 1 line
2.17.1
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 18 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.
Quoted 8 lines
This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Could this maybe be efi=disable_early_pci_dma?
As it stands, it reads like busmastering is turned off and stays off, which is not the case. I'm dreading the silly forum posts saying "your system is slow, and busmastering is leet, so use efi=no_disable_pci_dma to allow busmastering and make it OMG fast".
--Andy
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 29 lines · Andy Lutomirski
Quoted 18 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.Quoted 8 lines
This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 7 lines
Could this maybe be efi=disable_early_pci_dma?
As it stands, it reads like busmastering is turned off and stays off, which is not the case. I'm dreading the silly forum posts saying "your system is slow, and busmastering is leet, so use efi=no_disable_pci_dma to allow busmastering and make it OMG fast".
Fair enough. I'll change this to [no_]disable_early_pci_dma (assuming Matthew doesn't object to the exact shade of this bikeshed)
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 2 lines · Ard Biesheuvel
Fair enough. I'll change this to [no_]disable_early_pci_dma (assuming Matthew doesn't object to the exact shade of this bikeshed)
I'm fine with that.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
In reply to Ard Biesheuveldrivers/firmware/efi/libstub/pci.c line 110
Quoted 7 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }
OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 10 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 7 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }
Quoted 3 lines
OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before ExitBootServices() returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
So this approach is what i am willing to accept for mainline, and I would even start out by enabling it by default to get the most coverage. If you need something stronger, I understand but I don't think it belongs in mainline.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 19 lines · Ard Biesheuvel
Quoted 10 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 9 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }Quoted 3 lines
OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
Quoted 6 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
Can you clarify (in the changelog or a comment perhaps) why you’re doing this instead of turning off busmastering before calling ExitBootServices()? Maybe this was covered in this thread, but I missed it.
Also, surely this whole mess is a a design error in EFI, at least when SEV is involved, and there should be an EFI extension to keep IOMMU enabled. Or a specified way to *guarantee* that DMA is off when we exit boot services without hackery.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 20 lines · Andy Lutomirski
Quoted 20 lines · Ard Biesheuvel
Quoted 13 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 9 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
Quoted 9 lines
Quoted 6 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.Can you clarify (in the changelog or a comment perhaps) why you’re doing this instead of turning off busmastering before calling
ExitBootServices()? Maybe this was covered in this thread, but I missed it.
Sure. The problem is that EBS() is the place where drivers tear down rings etc and gracefully take down the device. So killing DMA for all of them by clearing the BM bit of every bridge is likely to cause problems, because the teardown code wasn't written with the idea in mind that DMA is no longer possible. On arm64 at least, it may result in the kernel being entered with a pending SError which will kill the OS as soon as they are unmasked. But the UEFI drivers themselves may simply hang or timeout on some DMA access.
Quoted 1 line
Also, surely this whole mess is a a design error in EFI, at least when SEV is involved, and there should be an EFI extension to keep IOMMU enabled. Or a specified way to *guarantee* that DMA is off when we exit boot services without hackery.
The UEFI spec requires that all devices stop doing DMA at ExitBootServices() time, which is why they register for this event and disable DMA in their drivers. So from this pov, the state of the IOMMU is irrelevant since no device should be doing DMA anyway. The UEFI spec does not reason at all about IOMMUs.
But indeed, the whole idea that the IOMMU is a 'feature' that you can ignore if you want since it will be in passthrough mode otherwise is misguided, but I'm not sure this is a firmware problem. The desire to be able to run yesterday's OS on today's hardware, especially in the Windows world, resulted in a situation where many security and hardening features are opt-in rather than opt-out, with the adoption you might expect.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Andy Lutomirski
Quoted 20 lines · Ard Biesheuvel
Quoted 13 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 9 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
Could we add a comment to describe why we have the two-step event notification, i.e. to ensure the ordering?
Regarding SEV, from what Laszlo had said [1] I had understood that the SEV driver left everything blacklisted -- is this necessary at all for SEV or did I misunderstand his comment?
[1] https://lore.kernel.org/lkml/[email protected]/
Quoted 4 lines
Quoted 3 lines
Can you clarify (in the changelog or a comment perhaps) why you’re doing this instead of turning off busmastering before calling
ExitBootServices()? Maybe this was covered in this thread, but I missed it.
Quoted 9 lines
Sure. The problem is that
EBS()is the place where drivers tear down rings etc and gracefully take down the device. So killing DMA for all of them by clearing the BM bit of every bridge is likely to cause problems, because the teardown code wasn't written with the idea in mind that DMA is no longer possible. On arm64 at least, it may result in the kernel being entered with a pending SError which will kill the OS as soon as they are unmasked. But the UEFI drivers themselves may simply hang or timeout on some DMA access.
As I understand it, the order in which we want the bus-mastering disable to happen is
- all PCI device drivers are stopped
- bus mastering is disabled
- depending on firmware, iommu might get disabled (probably out of our control)
Instead of using the event notifier, could we not explicitly call DisconnectController() for all the PCI devices, then disable bus-mastering, and only then call ExitBootServices()?
Quoted 8 lines
Quoted 1 line
Also, surely this whole mess is a a design error in EFI, at least when SEV is involved, and there should be an EFI extension to keep IOMMU enabled. Or a specified way to *guarantee* that DMA is off when we exit boot services without hackery.
The UEFI spec requires that all devices stop doing DMA at
ExitBootServices()time, which is why they register for this event and disable DMA in their drivers. So from this pov, the state of the IOMMU is irrelevant since no device should be doing DMA anyway. The UEFI spec does not reason at all about IOMMUs.
Quoted 7 lines
But indeed, the whole idea that the IOMMU is a 'feature' that you can ignore if you want since it will be in passthrough mode otherwise is misguided, but I'm not sure this is a firmware problem. The desire to be able to run yesterday's OS on today's hardware, especially in the Windows world, resulted in a situation where many security and hardening features are opt-in rather than opt-out, with the adoption you might expect.
Looking at the intel iommu driver [2] there is a PCD entry to control whether to leave the IOMMU enabled. Is it possible to check its value to see whether the bus-master disabling is necessary -- ie IOMMU was enabled during boot and its going to get turned off during ExitBootServices, or even check whether it's settable and if so set it to leave the IOMMU enabled?
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 29 lines · Arvind Sankar
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Andy Lutomirski
Quoted 20 lines · Ard Biesheuvel
Quoted 13 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 9 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
Quoted 8 lines
Could we add a comment to describe why we have the two-step event notification, i.e. to ensure the ordering?
Regarding SEV, from what Laszlo had said [1] I had understood that the SEV driver left everything blacklisted -- is this necessary at all for SEV or did I misunderstand his comment?
Leaving all guest RAM encrypted after EBS may not be a technical requirement for SEV. It is a security goal, however. The OS should inherit the most secure environment possible from the firmware, and not have to look for pages that were left unencrypted.
Quoted 20 lines
Quoted 12 lines
Quoted 2 lines
Can you clarify (in the changelog or a comment perhaps) why you’re doing this instead of turning off busmastering before calling
ExitBootServices()? Maybe this was covered in this thread, but I missed it.Sure. The problem is that
EBS()is the place where drivers tear down rings etc and gracefully take down the device. So killing DMA for all of them by clearing the BM bit of every bridge is likely to cause problems, because the teardown code wasn't written with the idea in mind that DMA is no longer possible. On arm64 at least, it may result in the kernel being entered with a pending SError which will kill the OS as soon as they are unmasked. But the UEFI drivers themselves may simply hang or timeout on some DMA access.As I understand it, the order in which we want the bus-mastering disable to happen is
- all PCI device drivers are stopped
- bus mastering is disabled
- depending on firmware, iommu might get disabled (probably out of our control)
Quoted 3 lines
Instead of using the event notifier, could we not explicitly call
DisconnectController()for all the PCI devices, then disable bus-mastering, and only then callExitBootServices()?
This sounds worth investigating to me.
Quoted 16 lines
Quoted 8 lines
Quoted 1 line
Also, surely this whole mess is a a design error in EFI, at least when SEV is involved, and there should be an EFI extension to keep IOMMU enabled. Or a specified way to *guarantee* that DMA is off when we exit boot services without hackery.
The UEFI spec requires that all devices stop doing DMA at
ExitBootServices()time, which is why they register for this event and disable DMA in their drivers. So from this pov, the state of the IOMMU is irrelevant since no device should be doing DMA anyway. The UEFI spec does not reason at all about IOMMUs.Quoted 7 lines
But indeed, the whole idea that the IOMMU is a 'feature' that you can ignore if you want since it will be in passthrough mode otherwise is misguided, but I'm not sure this is a firmware problem. The desire to be able to run yesterday's OS on today's hardware, especially in the Windows world, resulted in a situation where many security and hardening features are opt-in rather than opt-out, with the adoption you might expect.
Quoted 9 lines
Looking at the intel iommu driver [2] there is a PCD entry to control whether to leave the IOMMU enabled. Is it possible to check its value to see whether the bus-master disabling is necessary -- ie IOMMU was enabled during boot and its going to get turned off during ExitBootServices, or even check whether it's settable and if so set it to leave the IOMMU enabled?
The platform config database is a PI concept, not a UEFI concept. IOW, EFI_PCD_PROTOCOL is specified in the Platform Init spec, and not the UEFI spec. A UEFI OS should only rely on the UEFI spec.
Thanks
Laszlo
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 65 lines · Laszlo Ersek
Quoted 29 lines · Arvind Sankar
Quoted 21 lines · Ard Biesheuvel
Quoted 20 lines · Andy Lutomirski
Quoted 20 lines · Ard Biesheuvel
Quoted 13 lines · Matthew Garrett
Review
Quoted 9 lines · Ard Biesheuvel
(quoted diff) +7
-0+ status = efi_call_early(create_event, EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_CALLBACK, handle_exit_boot_services_event, + NULL, &exit_boot_services_event); + if (status != EFI_SUCCESS) { + pr_efi_err("Failed to register for EBS() event\n"); + goto free_handle; + }OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.Quoted 8 lines
Could we add a comment to describe why we have the two-step event notification, i.e. to ensure the ordering?
Regarding SEV, from what Laszlo had said [1] I had understood that the SEV driver left everything blacklisted -- is this necessary at all for SEV or did I misunderstand his comment?
Leaving all guest RAM encrypted after EBS may not be a technical requirement for SEV. It is a security goal, however. The OS should inherit the most secure environment possible from the firmware, and not have to look for pages that were left unencrypted.
Quoted 20 lines
Quoted 12 lines
Quoted 2 lines
Can you clarify (in the changelog or a comment perhaps) why you’re doing this instead of turning off busmastering before calling
ExitBootServices()? Maybe this was covered in this thread, but I missed it.Sure. The problem is that
EBS()is the place where drivers tear down rings etc and gracefully take down the device. So killing DMA for all of them by clearing the BM bit of every bridge is likely to cause problems, because the teardown code wasn't written with the idea in mind that DMA is no longer possible. On arm64 at least, it may result in the kernel being entered with a pending SError which will kill the OS as soon as they are unmasked. But the UEFI drivers themselves may simply hang or timeout on some DMA access.As I understand it, the order in which we want the bus-mastering disable to happen is
- all PCI device drivers are stopped
- bus mastering is disabled
- depending on firmware, iommu might get disabled (probably out of our control)
Quoted 6 lines
Quoted 3 lines
Instead of using the event notifier, could we not explicitly call
DisconnectController()for all the PCI devices, then disable bus-mastering, and only then callExitBootServices()?This sounds worth investigating to me.
I implemented this here:
https://lore.kernel.org/linux-efi/[email protected]/
It works on all the systems I tried, including a mixed mode iMac 24" and a mixed mode Intel Atom based tablet kindly provided by Hans.
The only thing to keep in mind is that some drivers implement Gop->Blt() using DMA in some cases, and so we should ensure that this is really the last thing that happens before ExitBootServices() is called, since a simple efi_printk() may trigger a DMA access by the graphics hardware.
Quoted 23 lines
Quoted 23 lines
Quoted 8 lines
Quoted 1 line
Also, surely this whole mess is a a design error in EFI, at least when SEV is involved, and there should be an EFI extension to keep IOMMU enabled. Or a specified way to *guarantee* that DMA is off when we exit boot services without hackery.
The UEFI spec requires that all devices stop doing DMA at
ExitBootServices()time, which is why they register for this event and disable DMA in their drivers. So from this pov, the state of the IOMMU is irrelevant since no device should be doing DMA anyway. The UEFI spec does not reason at all about IOMMUs.Quoted 7 lines
But indeed, the whole idea that the IOMMU is a 'feature' that you can ignore if you want since it will be in passthrough mode otherwise is misguided, but I'm not sure this is a firmware problem. The desire to be able to run yesterday's OS on today's hardware, especially in the Windows world, resulted in a situation where many security and hardening features are opt-in rather than opt-out, with the adoption you might expect.
Looking at the intel iommu driver [2] there is a PCD entry to control whether to leave the IOMMU enabled. Is it possible to check its value to see whether the bus-master disabling is necessary -- ie IOMMU was enabled during boot and its going to get turned off during ExitBootServices, or even check whether it's settable and if so set it to leave the IOMMU enabled?
Quoted 7 lines
The platform config database is a PI concept, not a UEFI concept. IOW,
EFI_PCD_PROTOCOLis specified in the Platform Init spec, and not the UEFI spec. A UEFI OS should only rely on the UEFI spec.
Agreed. And on top of that, PCDs can be FixedAtBuild or Patchable, in which case they cannot be controlled via the EFI_PCD_PROTOCOL.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
In reply to Ard BiesheuvelQuoted 16 lines · Ard Biesheuvel
Quoted 10 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 7 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }Quoted 3 lines
OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?
Quoted 5 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
Hm. In that case, I think this version fails to match the patch description - there's potentially still a window where DMA-capable PCI devices can attack the kernel, it's just smaller. If disconnecting drivers from the device would give us the same expectations then that seems like a better approach, but I think I probably wouldn't add my signed-off-by to this version.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 25 lines · Matthew Garrett
Quoted 16 lines · Ard Biesheuvel
Quoted 10 lines · Matthew Garrett
drivers/firmware/efi/libstub/pci.c line 110
Quoted 7 lines · Ard Biesheuvel
drivers/firmware/efi/libstub/pci.c new file +7
-0+ status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + }Quoted 3 lines
OVMF's SEV implementation appears to tear down AMD's IOMMU mappings at
EVT_SIGNAL_EXIT_BOOT_SERVICES. How are we ensuring that this happens first?Quoted 5 lines
It doesn't, and that is kind of the point. The only guarantee you have is that this runs before
ExitBootServices()returns, but after any other callbacks that have been registered. I know this is not 100% what you're after, but it is the only way we can avoid poking devices behind the backs of their drivers.
Quoted 6 lines
Hm. In that case, I think this version fails to match the patch description - there's potentially still a window where DMA-capable PCI devices can attack the kernel, it's just smaller. If disconnecting drivers from the device would give us the same expectations then that seems like a better approach, but I think I probably wouldn't add my signed-off-by to this version.
Point taken. I like Arvind's suggestion but we need to take care not to disable the device producing the GOP. Beyond that, it should be possible to disable all devices that are behind PCI bridges. It does mean we need to decode the secondary/subordinate bus values from the config space and take them into account when iterating over the PCI handle list.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 6 lines · Ard Biesheuvel
Point taken. I like Arvind's suggestion but we need to take care not to disable the device producing the GOP. Beyond that, it should be possible to disable all devices that are behind PCI bridges. It does mean we need to decode the secondary/subordinate bus values from the config space and take them into account when iterating over the PCI handle list.
The device producing the GOP is the device that I'm most afraid of, to be honest.I'd naively expect that anything presenting a linear framebuffer will probably leave it up at disconnect time, and we're definitely not using DMA to access that framebuffer.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 8 lines · Matthew Garrett
Quoted 6 lines · Ard Biesheuvel
Point taken. I like Arvind's suggestion but we need to take care not to disable the device producing the GOP. Beyond that, it should be possible to disable all devices that are behind PCI bridges. It does mean we need to decode the secondary/subordinate bus values from the config space and take them into account when iterating over the PCI handle list.
Why do we need to look at the bus numbers? Shouldn't it be just looping and disabling everything that's a regular device in the first pass (possibly excluding devices that are producing GOP/UGA), and then going over it again to disable the bus-master settings on bridges?
Also, why do we restrict the bus-master disable to only PCI/PCI bridges? Shouldn't we also disable bus-mastering on all the other PCI-xxx bridges?
Quoted 5 lines
The device producing the GOP is the device that I'm most afraid of, to be honest.I'd naively expect that anything presenting a linear framebuffer will probably leave it up at disconnect time, and we're definitely not using DMA to access that framebuffer.
At least on my system, disconnecting the GOP device does leave the display up, and the framebuffer remains active (ie writing to it updates the display). It wouldn't be surprising if this doesn't work for all GPUs though.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 11 lines · Arvind Sankar
Quoted 8 lines · Matthew Garrett
Quoted 6 lines · Ard Biesheuvel
Point taken. I like Arvind's suggestion but we need to take care not to disable the device producing the GOP. Beyond that, it should be possible to disable all devices that are behind PCI bridges. It does mean we need to decode the secondary/subordinate bus values from the config space and take them into account when iterating over the PCI handle list.
Quoted 5 lines
Why do we need to look at the bus numbers? Shouldn't it be just looping and disabling everything that's a regular device in the first pass (possibly excluding devices that are producing GOP/UGA), and then going over it again to disable the bus-master settings on bridges?
Yeah, that would work I guess
Quoted 4 lines
Also, why do we restrict the bus-master disable to only PCI/PCI bridges? Shouldn't we also disable bus-mastering on all the other PCI-xxx bridges?
Practically, on PCIe systems, PCI/PCI bridges are the only thing we need to care about, since that is how PCIe root ports are modelled.
Quoted 11 lines
Quoted 5 lines
The device producing the GOP is the device that I'm most afraid of, to be honest.I'd naively expect that anything presenting a linear framebuffer will probably leave it up at disconnect time, and we're definitely not using DMA to access that framebuffer.
At least on my system, disconnecting the GOP device does leave the display up, and the framebuffer remains active (ie writing to it updates the display). It wouldn't be surprising if this doesn't work for all GPUs though.
Disconnecting a device should result in the protocols installed by the driver to be removed again, and this also applies to the GOP protocol. Whether or not the framebuffer is still live after that point is not entirely relevant.
But if the GOP it produces is not BltOnly and its framebuffer address doesn't intersect system memory, it should be safe to disable DMA on such devices.
So in summary, we'll need to do
for each PCI I/O handle {
if (bus == 0 || // not behind a bridge
type == bridge)
ignore;
else
disconnect();
}for each PCI I/O handle {
if (type == bridge)
disable BM bit; }
Disregarding bus 0 means all the 'special' devices integrated into the root complex are disregarded as well, which seems safer to me.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 3 lines · Ard Biesheuvel
Practically, on PCIe systems, PCI/PCI bridges are the only thing we need to care about, since that is how PCIe root ports are modelled.
If I'm interpreting my lspci output correctly, I have a PCI/ISA bridge on bus 0 that's not behind a PCI/PCI bridge. Device 1f.0 below is the PCI/ISA bridge. Devices 1-3 are the CPU root ports and 1c.* are the chipset root ports.
Also, what about for eg, the USB or SATA controllers? I know that someone had said earlier that disabling BM on endpoints is pointless as malicious endpoints could just re-enable it, but is it not possible for malicious USB devices/SATA devices to try to use DMA through those controllers? ie if we trust the controllers since they're on-board, but not necessarily the devices behind them, wouldn't it still be worth it to disable BM on the controllers too?
$ lspci -tv -s 0:0:
-[0000:00]-+-00.0 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2
+-01.0-[01]--
+-01.1-[02]--
+-02.0-[03]--
+-02.2-[04]--
+-03.0-[05]--
+-03.2-[06-09]--
+-05.0 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Map/VTd_Misc/System Management
+-05.1 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Hot Plug
+-05.2 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO RAS/Control Status/Global Errors
+-05.4 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC
+-11.0 Intel Corporation C610/X99 series chipset SPSR
+-11.4 Intel Corporation C610/X99 series chipset sSATA Controller [AHCI mode]
+-14.0 Intel Corporation C610/X99 series chipset USB xHCI Host Controller
+-16.0 Intel Corporation C610/X99 series chipset MEI Controller #1
+-16.1 Intel Corporation C610/X99 series chipset MEI Controller #2
+-1a.0 Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #2
+-1b.0 Intel Corporation C610/X99 series chipset HD Audio Controller
+-1c.0-[0a]--
+-1c.2-[0b]--
+-1c.3-[0c]--
+-1c.4-[0d]--
+-1c.7-[0e-0f]--
+-1d.0 Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #1
+-1f.0 Intel Corporation C610/X99 series chipset LPC Controller
+-1f.2 Intel Corporation C610/X99 series chipset 6-Port SATA Controller [AHCI mode]
\-1f.3 Intel Corporation C610/X99 series chipset SMBus ControllerRe: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 9 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Practically, on PCIe systems, PCI/PCI bridges are the only thing we need to care about, since that is how PCIe root ports are modelled.
If I'm interpreting my lspci output correctly, I have a PCI/ISA bridge on bus 0 that's not behind a PCI/PCI bridge. Device 1f.0 below is the PCI/ISA bridge.
Yeah, this is the LPC controller, right? What devices are actually on that bus that are not closely tied to the chipset?
Quoted 3 lines
Devices 1-3 are the CPU root ports and 1c.* are the chipset root ports.
Right.
Quoted 8 lines
Also, what about for eg, the USB or SATA controllers? I know that someone had said earlier that disabling BM on endpoints is pointless as malicious endpoints could just re-enable it, but is it not possible for malicious USB devices/SATA devices to try to use DMA through those controllers? ie if we trust the controllers since they're on-board, but not necessarily the devices behind them, wouldn't it still be worth it to disable BM on the controllers too?
At this point, it probably makes sense to clarify what the threat model is. I have been assuming (but Matthew should confirm) that we're primarily concerned with DMA attacks over, e.g., Thunderbolt ports, in which case managing the BM bit at the root port level should be sufficient.
If there are other things we want to address (or if my assumption was incorrect), we should clarify this first, before deciding what the right mitigation would be.
Quoted 29 lines
$ lspci -tv -s 0:0:
-[0000:00]-+-00.0 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D DMI2
+-01.0-[01]--
+-01.1-[02]--
+-02.0-[03]--
+-02.2-[04]--
+-03.0-[05]--
+-03.2-[06-09]--
+-05.0 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Map/VTd_Misc/System Management
+-05.1 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO Hot Plug
+-05.2 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D IIO RAS/Control Status/Global Errors
+-05.4 Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D I/O APIC
+-11.0 Intel Corporation C610/X99 series chipset SPSR
+-11.4 Intel Corporation C610/X99 series chipset sSATA Controller [AHCI mode]
+-14.0 Intel Corporation C610/X99 series chipset USB xHCI Host Controller
+-16.0 Intel Corporation C610/X99 series chipset MEI Controller #1
+-16.1 Intel Corporation C610/X99 series chipset MEI Controller #2
+-1a.0 Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #2
+-1b.0 Intel Corporation C610/X99 series chipset HD Audio Controller
+-1c.0-[0a]--
+-1c.2-[0b]--
+-1c.3-[0c]--
+-1c.4-[0d]--
+-1c.7-[0e-0f]--
+-1d.0 Intel Corporation C610/X99 series chipset USB Enhanced Host Controller #1
+-1f.0 Intel Corporation C610/X99 series chipset LPC Controller
+-1f.2 Intel Corporation C610/X99 series chipset 6-Port SATA Controller [AHCI mode]
\-1f.3 Intel Corporation C610/X99 series chipset SMBus ControllerRe: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 7 lines · Ard Biesheuvel
Quoted 6 lines · Arvind Sankar
Quoted 3 lines · Ard Biesheuvel
Practically, on PCIe systems, PCI/PCI bridges are the only thing we need to care about, since that is how PCIe root ports are modelled.
Quoted 7 lines
Quoted 3 lines
If I'm interpreting my lspci output correctly, I have a PCI/ISA bridge on bus 0 that's not behind a PCI/PCI bridge. Device 1f.0 below is the PCI/ISA bridge.
Yeah, this is the LPC controller, right? What devices are actually on that bus that are not closely tied to the chipset?
AFAICT it's my BMC's IPMI interface and some sort of watchdog I think -- don't have drivers but there are three other ACPI PNP* nodes under there as well.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
In reply to Arvind SankarQuoted 7 lines · Arvind Sankar
Also, what about for eg, the USB or SATA controllers? I know that someone had said earlier that disabling BM on endpoints is pointless as malicious endpoints could just re-enable it, but is it not possible for malicious USB devices/SATA devices to try to use DMA through those controllers? ie if we trust the controllers since they're on-board, but not necessarily the devices behind them, wouldn't it still be worth it to disable BM on the controllers too?
The concern is DMA initiated by a hostile device. SATA and USB don't permit the devices themselves to initiate DMA, whereas PCI does.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
In reply to Ard BiesheuvelHi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>
I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have CONFIG_EFI_DISABLE_PCI_DMA=y and that that was causing it and indeed that is the problem.
So as (somewhat) expected CONFIG_EFI_DISABLE_PCI_DMA=y indeed stops the kernel from booting on some systems.
When I hit this problem the efistub prints 2 messages and then the system just hangs:
exit_boot() failed!efi_main() failed!
When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Regards,
Hans
Quoted 286 lines
--- Documentation/admin-guide/kernel-parameters.txt | 4 + arch/x86/boot/compressed/eboot.c | 2 + drivers/firmware/efi/Kconfig | 22 ++++ drivers/firmware/efi/libstub/Makefile | 2 +- drivers/firmware/efi/libstub/arm-stub.c | 1 + drivers/firmware/efi/libstub/efi-stub-helper.c | 17 +++ drivers/firmware/efi/libstub/efistub.h | 1 + drivers/firmware/efi/libstub/pci.c | 116 ++++++++++++++++++++ include/linux/efi.h | 2 + 9 files changed, 166 insertions(+), 1 deletion(-)Documentation/admin-guide/kernel-parameters.txt +4
-0@@ -1180,6 +1180,10 @@ claim. Specify efi=nosoftreserve to disable this reservation and treat the memory by its base type (i.e. EFI_CONVENTIONAL_MEMORY / "System RAM"). + disable_pci_dma: Disable the busmaster bit on all + PCI bridges while in the EFI boot stub + no_disable_pci_dma: Leave the busmaster bit set on all + PCI bridges while in the EFI boot stub efi_no_storage_paranoia [EFI; X86] Using this parameter you can use more than 50% ofarch/x86/boot/compressed/eboot.c +2
-0@@ -126,6 +126,8 @@ static void setup_efi_pci(struct boot_params *params)efi_handle_t h;int i; +efi_pci_disable_bridge_busmaster (); + status =efi_call_early (locate_handle,EFI_LOCATE_BY_PROTOCOL , &pci_proto,NULL , &size, pci_handle);drivers/firmware/efi/Kconfig +22
-0@@ -215,6 +215,28 @@ config EFI_RCI2_TABLE Say Y here for Dell EMC PowerEdge systems. +config EFI_DISABLE_PCI_DMA + bool "Clear Busmaster bit on PCI bridges during ExitBootServices()" + help + Disable the busmaster bit in the control register on all PCI bridges + while calling ExitBootServices() and passing control to the runtime + kernel. System firmware may configure the IOMMU to prevent malicious + PCI devices from being able to attack the OS via DMA. However, since + firmware can't guarantee that the OS is IOMMU-aware, it will tear + down IOMMU configuration when ExitBootServices() is called. This + leaves a window between where a hostile device could still cause + damage before Linux configures the IOMMU again. + + If you say Y here, the EFI stub will clear the busmaster bit on all + PCI bridges before ExitBootServices() completes. This will prevent + any malicious PCI devices from being able to perform DMA until the + kernel reenables busmastering after configuring the IOMMU. + + This option will cause failures with some poorly behaved hardware + and should not be enabled without testing. The kernel commandline + options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be + used to override this option. + endmenu config UEFI_CPERdrivers/firmware/efi/libstub/Makefile +1
-1@@ -39,7 +39,7 @@ OBJECT_FILES_NON_STANDARD := y KCOV_INSTRUMENT := n lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ - random.o + random.o pci.o # include the stub's generic dependencies from lib/ when building for ARM/arm64 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.cdrivers/firmware/efi/libstub/arm-stub.c +1
-0@@ -257,6 +257,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg, }install_memreserve_table (); +efi_pci_disable_bridge_busmaster (); new_fdt_addr = fdt_addr; status = allocate_new_fdt_and_exit_boot(handle,drivers/firmware/efi/libstub/efi-stub-helper.c +17
-0@@ -33,6 +33,8 @@ static bool __section(.data) efi_nokaslr; static bool __section(.data) efi_quiet; static bool __section(.data) efi_novamap; static bool __section(.data) efi_nosoftreserve; +static bool __section(.data) efi_disable_pci_dma = +IS_ENABLED (CONFIG_EFI_DISABLE_PCI_DMA ); bool __pure nokaslr(void) {@@ -51,6 +53,11 @@ bool __pure __efi_soft_reserve_enabled(void)return !efi_nosoftreserve; } +bool __pure disable_pci_dma (void ) +{ +return efi_disable_pci_dma; +} +#define EFI_MMAP_NR_SLACK_SLOTS 8struct file_info {@@ -499,6 +506,16 @@ efi_status_t efi_parse_options(char const *cmdline) efi_nosoftreserve = true; } +if (!strncmp (str,"disable_pci_dma" ,15 )) { + str +=strlen ("disable_pci_dma" ); + efi_disable_pci_dma = true; + } + +if (!strncmp (str,"no_disable_pci_dma" ,18 )) { + str +=strlen ("no_disable_pci_dma" ); + efi_disable_pci_dma = false; + } +/* Group words together, delimited by "," */ while (*str && *str !=' ' && *str !=',' ) str++;drivers/firmware/efi/libstub/efistub.h +1
-0@@ -28,6 +28,7 @@extern bool __pure nokaslr (void );extern bool __pure is_quiet (void );extern bool __pure novamap (void ); +extern bool __pure disable_pci_dma (void );extern __pure efi_system_table_t *efi_system_table (void );drivers/firmware/efi/libstub/pci.c new file +116
-0@@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* PCI-related functions used by the EFI stub on multiple +* architectures. +* +* Copyright 2019 Google, LLC +*/ + +#include <linux/efi.h> +#include <linux/pci.h> + +#include <asm/efi.h> + +#include "efistub.h" + +static efi_event_t __section(.data) exit_boot_services_event; +static efi_event_t __section(.data) disable_pci_dma_event; + +static efi_handle_t *__section(.data) pci_handle; +static unsigned long __section(.data) pci_handle_size; + +static efi_guid_t pci_proto =EFI_PCI_IO_PROTOCOL_GUID ; + +static void __efiapi handle_exit_boot_services_event(efi_event_t event, + void *context) +{ +efi_call_early (signal_event ,disable_pci_dma_event ); +} + +static void __efiapi handle_disable_pci_dma_event(efi_event_t event, + void *context) +{ +efi_handle_t handle; +efi_status_t status; +u16 class, command; +int i; + +for_each_efi_handle (handle, pci_handle, pci_handle_size, i) { +efi_pci_io_protocol_t *pci =NULL ; + + status =efi_call_early (handle_protocol, handle, + &pci_proto, (void **)&pci); +if (status !=EFI_SUCCESS || !pci) +continue ; + + status =efi_call_proto (pci, pci.read, EfiPciIoWidthUint16, +PCI_CLASS_DEVICE ,1 , &class); + +if (status !=EFI_SUCCESS || class !=PCI_CLASS_BRIDGE_PCI ) +continue ; + +/* Disable busmastering */ + status =efi_call_proto (pci, pci.read, EfiPciIoWidthUint16, +PCI_COMMAND ,1 , &command); +if (status !=EFI_SUCCESS || !(command &PCI_COMMAND_MASTER )) +continue ; + + command &= ~PCI_COMMAND_MASTER ; + status =efi_call_proto (pci, pci.write, EfiPciIoWidthUint16, +PCI_COMMAND ,1 , &command); +if (status !=EFI_SUCCESS ) +pr_efi_err ("Failed to disable PCI busmastering\n" ); + } +} + +void efi_pci_disable_bridge_busmaster (void ) +{ +efi_status_t status; + +if (!disable_pci_dma () || !efi_is_native ()) +return ; + + status =efi_call_early (locate_handle,EFI_LOCATE_BY_PROTOCOL , + &pci_proto,NULL , &pci_handle_size, pci_handle); + +if (status !=EFI_BUFFER_TOO_SMALL ) { +if (status !=EFI_SUCCESS && status !=EFI_NOT_FOUND ) +pr_efi_err ("Failed to locate PCI I/O handles'\n" ); +return ; + } + + status =efi_call_early (allocate_pool,EFI_LOADER_DATA , + pci_handle_size, (void **)&pci_handle); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to allocate memory for 'pci_handle'\n" ); +return ; + } + + status =efi_call_early (locate_handle,EFI_LOCATE_BY_PROTOCOL , + &pci_proto,NULL , &pci_handle_size, pci_handle); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to locate PCI I/O handles'\n" ); + goto free_handle; + } + + status =efi_call_early (create_event,EVT_NOTIFY_SIGNAL , +TPL_CALLBACK , handle_disable_pci_dma_event, +NULL , &disable_pci_dma_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to create event to disable PCI DMA\n" ); + goto free_handle; + } + + status =efi_call_early (create_event,EVT_SIGNAL_EXIT_BOOT_SERVICES , +TPL_CALLBACK , handle_exit_boot_services_event, +NULL , &exit_boot_services_event); +if (status !=EFI_SUCCESS ) { +pr_efi_err ("Failed to register for EBS() event\n" ); + goto free_handle; + } + +return ; + +free_handle: +efi_call_early (free_pool, pci_handle); +}include/linux/efi.h +2
-0@@ -1786,4 +1786,6 @@ struct linux_efi_memreserve {#define EFI_MEMRESERVE_COUNT (size) (((size) - sizeof(struct linux_efi_memreserve)) \ / sizeof(((struct linux_efi_memreserve *)0)->entry[0])) +void efi_pci_disable_bridge_busmaster (void ); +#endif /* _LINUX_EFI_H */
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 52 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have
CONFIG_EFI_DISABLE_PCI_DMA=yand that that was causing it and indeed that is the problem.So as (somewhat) expected
CONFIG_EFI_DISABLE_PCI_DMA=yindeed stops the kernel from booting on some systems.When I hit this problem the efistub prints 2 messages and then the system just hangs:
Quoted 9 lines
exit_boot()failed!efi_main()failed!When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Thanks Hans.
Can you run the UEFI shell on this system? If so, could you share the output of devtree, both in the docked and the undocked states?
That should help us pinpoint which device is throwing an error at ExitBootServices() time due to its driver having been disconnected.
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Hi,
Quoted 63 lines · Ard Biesheuvel
Quoted 52 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have
CONFIG_EFI_DISABLE_PCI_DMA=yand that that was causing it and indeed that is the problem.So as (somewhat) expected
CONFIG_EFI_DISABLE_PCI_DMA=yindeed stops the kernel from booting on some systems.When I hit this problem the efistub prints 2 messages and then the system just hangs:
Quoted 9 lines
exit_boot()failed!efi_main()failed!When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Quoted 7 lines
Thanks Hans.
Can you run the UEFI shell on this system? If so, could you share the output of devtree, both in the docked and the undocked states?
That should help us pinpoint which device is throwing an error at
ExitBootServices()time due to its driver having been disconnected.
Sorry for being slow to respond. Attached are the outputs of devtree in both states. Not sure if the list will accept this, but you should get a direct copy.
Regards,
Hans
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 72 lines · Hans de Goede
Hi,
Quoted 68 lines · Ard Biesheuvel
Quoted 52 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have
CONFIG_EFI_DISABLE_PCI_DMA=yand that that was causing it and indeed that is the problem.So as (somewhat) expected
CONFIG_EFI_DISABLE_PCI_DMA=yindeed stops the kernel from booting on some systems.When I hit this problem the efistub prints 2 messages and then the system just hangs:
Quoted 9 lines
exit_boot()failed!efi_main()failed!When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Thanks Hans.
Can you run the UEFI shell on this system? If so, could you share the output of devtree, both in the docked and the undocked states?
Quoted 7 lines
Quoted 2 lines
That should help us pinpoint which device is throwing an error at
ExitBootServices()time due to its driver having been disconnected.Sorry for being slow to respond. Attached are the outputs of devtree in both states. Not sure if the list will accept this, but you should get a direct copy.
Interesting. The only difference that UEFI seems to know about in terms of device hierarchy is a XHCI controller with a Realtek USB NIC attached.
Could you try unloading the driver for that manually, or disconnecting it? Or disconnect the whole thing from the shell?
If just unloading the realtek driver does not make a difference, but unload/disconnecting the xhci makes it work, it is likely that it this feature will break a lot of systems.
devtree-docked 2020-03-04 19:18:08.856257969 +0100 renamed from devtree-not-docked 2020-03-04 19:18:14.596315280 +0100 +14 -0
@@ -11,6 +11,7 @@ Ctrl[] PciRoot(0x0)/Pci(0x0,0x0) Ctrl[] Intel(R) Graphics Controller Ctrl[] EDP1 + Ctrl[] DP1 Ctrl[] Primary Console Output Device Ctrl[] PciRoot(0x0)/Pci(0x4,0x0) Ctrl[] PciRoot(0x0)/Pci(0x8,0x0)
@@ -44,6 +45,110 @@ Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x0,0x0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0) + Ctrl[] eXtensible Host Controller (USB 3.0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x4,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x2,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0)/USB(0x1,0x0) + Ctrl[] Realtek USB Ethernet Controller
<lots of network stuff>
+ Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x1) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x2) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x3) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x2,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0)/USB(0x1,0x0) + Ctrl[] Generic Usb Keyboard
+ Ctrl[] Primary Console Input Device
+ Ctrl[] Generic Usb Mouse
+ Ctrl[] Primary Console Input Device
+ Ctrl[] Generic Usb Mouse
+ Ctrl[] Primary Console Input Device
+ Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x4,0x0)
Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x2,0x0)
Ctrl[] eXtensible Host Controller (USB 3.0)
Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x4,0x0)@@ -69,5 +174,3 @@
Ctrl[] VenHw(2C0EEABD-4107-44A8-A787-2E38FFC52B2B) Ctrl[] VenHw(48B9FB42-B3B9-4A0E-BF66-36AE1C302369) Ctrl[] VenHw(A7F26116-CFDC-4296-8224-ED7D140170C7)
- Ctrl[] MemoryMapped(0xB,0xFF2E0000,0xFF37FFFF)
- Ctrl[] Fv(B92CF322-8AFA-4AA4-B946-005DF1D69778)
Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Hi,
Quoted 81 lines · Ard Biesheuvel
Quoted 72 lines · Hans de Goede
Hi,
Quoted 68 lines · Ard Biesheuvel
Quoted 52 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have
CONFIG_EFI_DISABLE_PCI_DMA=yand that that was causing it and indeed that is the problem.So as (somewhat) expected
CONFIG_EFI_DISABLE_PCI_DMA=yindeed stops the kernel from booting on some systems.When I hit this problem the efistub prints 2 messages and then the system just hangs:
Quoted 9 lines
exit_boot()failed!efi_main()failed!When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Thanks Hans.
Can you run the UEFI shell on this system? If so, could you share the output of devtree, both in the docked and the undocked states?
Quoted 7 lines
Quoted 2 lines
That should help us pinpoint which device is throwing an error at
ExitBootServices()time due to its driver having been disconnected.Sorry for being slow to respond. Attached are the outputs of devtree in both states. Not sure if the list will accept this, but you should get a direct copy.
Quoted 6 lines
Interesting. The only difference that UEFI seems to know about in terms of device hierarchy is a XHCI controller with a Realtek USB NIC attached.
Could you try unloading the driver for that manually, or disconnecting it? Or disconnect the whole thing from the shell?
How would I go about that / do that ?
Quoted 3 lines
If just unloading the realtek driver does not make a difference, but unload/disconnecting the xhci makes it work, it is likely that it this feature will break a lot of systems.
Notice that it is not just the XHCI controller which gets added though, there also is an extra PCI-e switch added to the route to the XHCI controller, I've attached both docked and undocked lspci output under Linux. I guess this might be transparent from a UEFI pov though.
Regards,
Hans
Quoted 47 lines
devtree-docked 2020-03-04 19:18:08.856257969 +0100 renamed from devtree-not-docked 2020-03-04 19:18:14.596315280 +0100 +14
-0@@ -11,6 +11,7 @@ Ctrl[] PciRoot(0x0)/Pci(0x0,0x0) Ctrl[] Intel(R) Graphics Controller Ctrl[] EDP1 + Ctrl[] DP1 Ctrl[] Primary Console Output Device Ctrl[] PciRoot(0x0)/Pci(0x4,0x0) Ctrl[] PciRoot(0x0)/Pci(0x8,0x0)@@ -44,6 +45,110 @@ Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x0,0x0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0) + Ctrl[] eXtensible Host Controller (USB 3.0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x4,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x2,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0)/USB(0x1,0x0) + Ctrl[] Realtek USB Ethernet Controller<lots of network stuff>
devtree-docked 2020-03-04 19:18:08.856257969 +0100 renamed from devtree-not-docked 2020-03-04 19:18:14.596315280 +0100 +14
-0+ Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x1) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x2) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x0,0x0)/USB(0x3,0x3) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x2,0x0)/USB(0x3,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0)/USB(0x0,0x0) + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x2,0x0)/Pci(0x0,0x0)/USB(0x1,0x0)/USB(0x0,0x0)/USB(0x3,0x0)/USB(0x1,0x0) + Ctrl[] Generic Usb Keyboard + Ctrl[] Primary Console Input Device + Ctrl[] Generic Usb Mouse + Ctrl[] Primary Console Input Device + Ctrl[] Generic Usb Mouse + Ctrl[] Primary Console Input Device + Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x4,0x0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x2,0x0) Ctrl[] eXtensible Host Controller (USB 3.0) Ctrl[] PciRoot(0x0)/Pci(0x1D,0x4)/Pci(0x0,0x0)/Pci(0x4,0x0)
devtree-docked 2020-03-04 19:18:08.856257969 +0100 line 73
Quoted 5 lines
devtree-docked 2020-03-04 19:18:08.856257969 +0100 renamed from devtree-not-docked 2020-03-04 19:18:14.596315280 +0100 +0
-2@@ -69,5 +174,3 @@ Ctrl[] VenHw(2C0EEABD-4107-44A8-A787-2E38FFC52B2B) Ctrl[] VenHw(48B9FB42-B3B9-4A0E-BF66-36AE1C302369) Ctrl[] VenHw(A7F26116-CFDC-4296-8224-ED7D140170C7) - Ctrl[] MemoryMapped(0xB,0xFF2E0000,0xFF37FFFF) - Ctrl[] Fv(B92CF322-8AFA-4AA4-B946-005DF1D69778)
00:00.0 Host bridge: Intel Corporation Coffee Lake HOST and DRAM Controller (rev 0c)
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (Whiskey Lake) (rev 02)
00:04.0 Signal processing controller: Intel Corporation Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem (rev 0c) 00:08.0 System peripheral: Intel Corporation Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model 00:12.0 Signal processing controller: Intel Corporation Cannon Point-LP Thermal Controller (rev 11)
00:14.0 USB controller: Intel Corporation Cannon Point-LP USB 3.1 xHCI Controller (rev 11)
00:14.2 RAM memory: Intel Corporation Cannon Point-LP Shared SRAM (rev 11)
00:14.3 Network controller: Intel Corporation Cannon Point-LP CNVi [Wireless-AC] (rev 11)
00:15.0 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP Serial IO I2C Controller #0 (rev 11) 00:15.1 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP Serial IO I2C Controller #1 (rev 11) 00:16.0 Communication controller: Intel Corporation Cannon Point-LP MEI Controller #1 (rev 11)
00:16.3 Serial controller: Intel Corporation Cannon Point-LP Keyboard and Text (KT) Redirection (rev 11) 00:1d.0 PCI bridge: Intel Corporation Cannon Point-LP PCI Express Root Port #9 (rev f1)
00:1d.4 PCI bridge: Intel Corporation Cannon Point-LP PCI Express Root Port #13 (rev f1)
00:1f.0 ISA bridge: Intel Corporation Cannon Point-LP LPC Controller (rev 11)
00:1f.3 Audio device: Intel Corporation Cannon Point-LP High Definition Audio Controller (rev 11)
00:1f.4 SMBus: Intel Corporation Cannon Point-LP SMBus Controller (rev 11)
00:1f.5 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP SPI Controller (rev 11)
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (6) I219-LM (rev 11)
03:00.0 Non-Volatile memory controller: Sandisk Corp WD Black 2018/PC SN720 NVMe SSD
05:00.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:00.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:01.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:02.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:04.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 07:00.0 System peripheral: Intel Corporation JHL6540 Thunderbolt 3 NHI (C step) [Alpine Ridge 4C 2016] (rev 02) 08:00.0 PCI bridge: Intel Corporation JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018] (rev 06)
09:02.0 PCI bridge: Intel Corporation JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018] (rev 06)
09:04.0 PCI bridge: Intel Corporation JHL7540 Thunderbolt 3 Bridge [Titan Ridge DD 2018] (rev 06)
0a:00.0 USB controller: Intel Corporation JHL7540 Thunderbolt 3 USB Controller [Titan Ridge 4C 2018] (rev 06) 2d:00.0 USB controller: Intel Corporation JHL6540 Thunderbolt 3 USB Controller (C step) [Alpine Ridge 4C 2016] (rev 02)
00:00.0 Host bridge: Intel Corporation Coffee Lake HOST and DRAM Controller (rev 0c)
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (Whiskey Lake) (rev 02)
00:04.0 Signal processing controller: Intel Corporation Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem (rev 0c) 00:08.0 System peripheral: Intel Corporation Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model 00:12.0 Signal processing controller: Intel Corporation Cannon Point-LP Thermal Controller (rev 11)
00:14.0 USB controller: Intel Corporation Cannon Point-LP USB 3.1 xHCI Controller (rev 11)
00:14.2 RAM memory: Intel Corporation Cannon Point-LP Shared SRAM (rev 11)
00:14.3 Network controller: Intel Corporation Cannon Point-LP CNVi [Wireless-AC] (rev 11)
00:15.0 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP Serial IO I2C Controller #0 (rev 11) 00:15.1 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP Serial IO I2C Controller #1 (rev 11) 00:16.0 Communication controller: Intel Corporation Cannon Point-LP MEI Controller #1 (rev 11)
00:16.3 Serial controller: Intel Corporation Cannon Point-LP Keyboard and Text (KT) Redirection (rev 11) 00:1d.0 PCI bridge: Intel Corporation Cannon Point-LP PCI Express Root Port #9 (rev f1)
00:1d.4 PCI bridge: Intel Corporation Cannon Point-LP PCI Express Root Port #13 (rev f1)
00:1f.0 ISA bridge: Intel Corporation Cannon Point-LP LPC Controller (rev 11)
00:1f.3 Audio device: Intel Corporation Cannon Point-LP High Definition Audio Controller (rev 11)
00:1f.4 SMBus: Intel Corporation Cannon Point-LP SMBus Controller (rev 11)
00:1f.5 Serial bus controller [0c80]: Intel Corporation Cannon Point-LP SPI Controller (rev 11)
00:1f.6 Ethernet controller: Intel Corporation Ethernet Connection (6) I219-LM (rev 11)
03:00.0 Non-Volatile memory controller: Sandisk Corp WD Black 2018/PC SN720 NVMe SSD
05:00.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:00.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:01.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:02.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 06:04.0 PCI bridge: Intel Corporation JHL6540 Thunderbolt 3 Bridge (C step) [Alpine Ridge 4C 2016] (rev 02) 07:00.0 System peripheral: Intel Corporation JHL6540 Thunderbolt 3 NHI (C step) [Alpine Ridge 4C 2016] (rev 02) 2d:00.0 USB controller: Intel Corporation JHL6540 Thunderbolt 3 USB Controller (C step) [Alpine Ridge 4C 2016] (rev 02)
-[0000:00]-+-00.0
+-02.0
+-04.0
+-08.0
+-12.0
+-14.0
+-14.2
+-14.3
+-15.0
+-15.1
+-16.0
+-16.3
+-1d.0-[03]----00.0
+-1d.4-[05-52]----00.0-[06-52]--+-00.0-[07]----00.0
| +-01.0-[08-2c]----00.0-[09-2c]--+-02.0-[0a]----00.0
| | \-04.0-[0b-2c]--
| +-02.0-[2d]----00.0
| \-04.0-[2e-52]--
+-1f.0
+-1f.3
+-1f.4
+-1f.5
\-1f.6
-[0000:00]-+-00.0
+-02.0
+-04.0
+-08.0
+-12.0
+-14.0
+-14.2
+-14.3
+-15.0
+-15.1
+-16.0
+-16.3
+-1d.0-[03]----00.0
+-1d.4-[05-52]----00.0-[06-52]--+-00.0-[07]----00.0
| +-01.0-[08-2c]--
| +-02.0-[2d]----00.0
| \-04.0-[2e-52]--
+-1f.0
+-1f.3
+-1f.4
+-1f.5
\-1f.6Re: [PATCH v2 21/21] efi: Allow disabling PCI busmastering on bridges during boot
Quoted 94 lines · Hans de Goede
Hi,
Quoted 81 lines · Ard Biesheuvel
Quoted 72 lines · Hans de Goede
Hi,
Quoted 68 lines · Ard Biesheuvel
Quoted 52 lines · Hans de Goede
Hi,
Quoted 26 lines · Ard Biesheuvel
From: Matthew Garrett <[email protected]>
Add an option to disable the busmaster bit in the control register on all PCI bridges during the invocation of
ExitBootServices()and passing control to the runtime kernel. System firmware may configure the IOMMU to prevent malicious PCI devices from being able to attack the OS via DMA. However, since firmware can't guarantee that the OS is IOMMU-aware, it will tear down IOMMU configuration whenExitBootServices()is called. This leaves a window between where a hostile device could still cause damage before Linux configures the IOMMU again.If
CONFIG_EFI_DISABLE_PCI_DMAis enabled or the "efi=disable_pci_dma" command line argument is passed, the EFI stub will clear the busmaster bit on all PCI bridges beforeExitBootServices()completes. This will prevent any malicious PCI devices from being able to perform DMA until the kernel reenables busmastering after configuring the IOMMU.This option is disabled when in EFI mixed mode environments (ie, 64-bit kernels with a 32-bit EFI implementation), given that the use of EFI events is not supported in this case.
This option may cause failures with some poorly behaved hardware and should not be enabled without testing. The kernel commandline options "efi=disable_pci_dma" or "efi=no_disable_pci_dma" may be used to override the default.
Quoted 4 lines
Co-developed-by Matthew Garrett <[email protected]>Signed-off-by Matthew Garrett <[email protected]>[ardb: use EFI events to defer DMA disabling to the end of ExitBootServices()]Signed-off-by Ard Biesheuvel <[email protected]>I guess this might not be the latest version of this patch, but this does seem to be the thread where most discussion on it has happened.
My personal kernel tree atm consists of v5.5 + efi/next + my own patches and yesterday I noticed that will not boot on a Lenovo X1 7th gen connected to a Lenovo thunderbolt 3 gen 2 dock.
My first hunch was that I have
CONFIG_EFI_DISABLE_PCI_DMA=yand that that was causing it and indeed that is the problem.So as (somewhat) expected
CONFIG_EFI_DISABLE_PCI_DMA=yindeed stops the kernel from booting on some systems.When I hit this problem the efistub prints 2 messages and then the system just hangs:
Quoted 9 lines
exit_boot()failed!efi_main()failed!When I boot the system without it being connected to the thunderbolt dock then efi=disable_pci_dma works fine.
Let me know if I can do anything to help and getting booting while connected to the dock to work with efi=disable_pci_dma.
Thanks Hans.
Can you run the UEFI shell on this system? If so, could you share the output of devtree, both in the docked and the undocked states?
Quoted 7 lines
Quoted 2 lines
That should help us pinpoint which device is throwing an error at
ExitBootServices()time due to its driver having been disconnected.Sorry for being slow to respond. Attached are the outputs of devtree in both states. Not sure if the list will accept this, but you should get a direct copy.
Quoted 6 lines
Interesting. The only difference that UEFI seems to know about in terms of device hierarchy is a XHCI controller with a Realtek USB NIC attached.
Could you try unloading the driver for that manually, or disconnecting it? Or disconnect the whole thing from the shell?
How would I go about that / do that ?
Quoted 9 lines
Quoted 3 lines
If just unloading the realtek driver does not make a difference, but unload/disconnecting the xhci makes it work, it is likely that it this feature will break a lot of systems.
Notice that it is not just the XHCI controller which gets added though, there also is an extra PCI-e switch added to the route to the XHCI controller, I've attached both docked and undocked lspci output under Linux. I guess this might be transparent from a UEFI pov though.
Yeah, what matters is drivers that are actually called when the EFI stub calls ExitBootServices(), and looking at the dump, the XHCI driver and the Realtek driver are the only ones that stand out to me (and the Realtek one is probably the only 3rd party driver, so that one looks the most suspect to me)
Hi,
Quoted 37 lines · Ard Biesheuvel
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.
Changes since v1:
- Substantially more cleanup work to simplify and hide the mixed mode handling in generic EFI code.
- Get rid of all the pointless passing around ofsys_table_arg
- Incorporate an updated version of Matthew's PCI DMA disable patch using EFI events to defer poking the busmaster bits until after all the ordinaryExitBootServices()callbacks have executed.Code can be found here
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-x86-cleanup-v2
Quoted 6 lines
Cc Hans de Goede <[email protected]>Cc Matthew Garrett <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Arvind Sankar <[email protected]>
I've merged ardb/efistub-x86-cleanup-v3 into my local tree for testing I will let you know if I see any unexpected side-effects. I've set CONFIG_EFI_DISABLE_PCI_DMA=n for now.
I did notice one small cosmetic issue with the last patch:
drivers/firmware/efi/Kconfig config EFI_RCI2_TABLE · line 220
Quoted 11 lines
drivers/firmware/efi/Kconfig +3
-0@@ -215,6 +215,28 @@ config EFI_RCI2_TABLE Say Y here for Dell EMC PowerEdge systems. +config EFI_DISABLE_PCI_DMA + bool "Clear Busmaster bit on PCI bridges during ExitBootServices()" + help
The bool and help here seem to be indented by 7 spaces rather then by a tab.
Regards,
Hans
Quoted 48 lines · Hans de Goede
Hi,
Quoted 37 lines · Ard Biesheuvel
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.
Changes since v1:
- Substantially more cleanup work to simplify and hide the mixed mode handling in generic EFI code.
- Get rid of all the pointless passing around ofsys_table_arg
- Incorporate an updated version of Matthew's PCI DMA disable patch using EFI events to defer poking the busmaster bits until after all the ordinaryExitBootServices()callbacks have executed.Code can be found here
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efistub-x86-cleanup-v2Quoted 6 lines
Cc Hans de Goede <[email protected]>Cc Matthew Garrett <[email protected]>Cc Ingo Molnar <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Arvind Sankar <[email protected]>
Quoted 4 lines
I've merged ardb/efistub-x86-cleanup-v3 into my local tree for testing I will let you know if I see any unexpected side-effects. I've set
CONFIG_EFI_DISABLE_PCI_DMA=nfor now.
Thanks Hans.
The CONFIG should not make a difference on mixed-mode - all the code is there anyway, and only the default value changes, but it is overridden to 'false' on mixed mode systems. The reason is that my version of this patch uses an event callback, which would mean 32-bit firmware calling back into the 64-bit kernel in the mixed mode case, which we don't support.
Quoted 21 lines
I did notice one small cosmetic issue with the last patch:
drivers/firmware/efi/Kconfig config EFI_RCI2_TABLE · line 220
Quoted 11 lines
drivers/firmware/efi/Kconfig +3
-0@@ -215,6 +215,28 @@ config EFI_RCI2_TABLE Say Y here for Dell EMC PowerEdge systems. +config EFI_DISABLE_PCI_DMA + bool "Clear Busmaster bit on PCI bridges during ExitBootServices()" + helpThe bool and help here seem to be indented by 7 spaces rather then by a tab.
Regards,
Hans