diff options
author | Ard Biesheuvel <ardb@kernel.org> | 2022-10-11 18:10:39 +0300 |
---|---|---|
committer | Ard Biesheuvel <ardb@kernel.org> | 2022-11-09 14:42:02 +0300 |
commit | 732ea9db9d8a6a0444d18ed810cccb2428d8766b (patch) | |
tree | 186ea3e313ea11d0d5edae397074828c263e98d6 /drivers/firmware/efi | |
parent | 06064800d92a1adac3717e86cc6ba5f98c0ef40e (diff) | |
download | linux-732ea9db9d8a6a0444d18ed810cccb2428d8766b.tar.xz |
efi: libstub: Move screen_info handling to common code
Currently, arm64, RISC-V and LoongArch rely on the fact that struct
screen_info can be accessed directly, due to the fact that the EFI stub
and the core kernel are part of the same image. This will change after a
future patch, so let's ensure that the screen_info handling is able to
deal with this, by adopting the arm32 approach of passing it as a
configuration table. While at it, switch to ACPI reclaim memory to hold
the screen_info data, which is more appropriate for this kind of
allocation.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'drivers/firmware/efi')
-rw-r--r-- | drivers/firmware/efi/efi-init.c | 21 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 5 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm32-stub.c | 37 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub.c | 9 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 3 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/screen_info.c | 56 |
7 files changed, 93 insertions, 41 deletions
diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index 2fd770b499a3..1639159493e3 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -22,6 +22,8 @@ #include <asm/efi.h> +unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; + static int __init is_memory(efi_memory_desc_t *md) { if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) @@ -55,9 +57,22 @@ extern __weak const efi_config_table_type_t efi_arch_tables[]; static void __init init_screen_info(void) { - if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && - memblock_is_map_memory(screen_info.lfb_base)) - memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); + struct screen_info *si; + + if (screen_info_table != EFI_INVALID_TABLE_ADDR) { + si = early_memremap(screen_info_table, sizeof(*si)); + if (!si) { + pr_err("Could not map screen_info config table\n"); + return; + } + screen_info = *si; + memset(si, 0, sizeof(*si)); + early_memunmap(si, sizeof(*si)); + + if (memblock_is_map_memory(screen_info.lfb_base)) + memblock_mark_nomap(screen_info.lfb_base, + screen_info.lfb_size); + } } static int __init uefi_init(u64 efi_system_table) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a46df5d1d094..951a42d27cf4 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -58,6 +58,8 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR; +extern unsigned long screen_info_table; + struct mm_struct efi_mm = { .mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock), .mm_users = ATOMIC_INIT(2), @@ -547,6 +549,9 @@ static const efi_config_table_type_t common_tables[] __initconst = { #ifdef CONFIG_EFI_COCO_SECRET {LINUX_EFI_COCO_SECRET_AREA_GUID, &efi.coco_secret, "CocoSecret" }, #endif +#ifdef CONFIG_EFI_GENERIC_STUB + {LINUX_EFI_SCREEN_INFO_TABLE_GUID, &screen_info_table }, +#endif {}, }; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5b0ae755180e..3f44e272ff9c 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -81,7 +81,8 @@ lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(call if_changed_rule,cc_o_c) -lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o +lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \ + screen_info.o lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c index 0131e3aaa605..1073dd947516 100644 --- a/drivers/firmware/efi/libstub/arm32-stub.c +++ b/drivers/firmware/efi/libstub/arm32-stub.c @@ -76,43 +76,6 @@ void efi_handle_post_ebs_state(void) &efi_entry_state->sctlr_after_ebs); } -static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID; - -struct screen_info *alloc_screen_info(void) -{ - struct screen_info *si; - efi_status_t status; - - /* - * Unlike on arm64, where we can directly fill out the screen_info - * structure from the stub, we need to allocate a buffer to hold - * its contents while we hand over to the kernel proper from the - * decompressor. - */ - status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA, - sizeof(*si), (void **)&si); - - if (status != EFI_SUCCESS) - return NULL; - - status = efi_bs_call(install_configuration_table, - &screen_info_guid, si); - if (status == EFI_SUCCESS) - return si; - - efi_bs_call(free_pool, si); - return NULL; -} - -void free_screen_info(struct screen_info *si) -{ - if (!si) - return; - - efi_bs_call(install_configuration_table, &screen_info_guid, NULL); - efi_bs_call(free_pool, si); -} - efi_status_t handle_kernel_image(unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index b55d1009d4c8..8521dc09c6ae 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -47,6 +47,15 @@ static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0); +struct screen_info * __weak alloc_screen_info(void) +{ + return &screen_info; +} + +void __weak free_screen_info(struct screen_info *si) +{ +} + static struct screen_info *setup_graphics(void) { efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index a30fb5d8ef05..a4cb51e2cae3 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -975,4 +975,7 @@ efi_enable_reset_attack_mitigation(void) { } void efi_retrieve_tpm2_eventlog(void); +struct screen_info *alloc_screen_info(void); +void free_screen_info(struct screen_info *si); + #endif diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c new file mode 100644 index 000000000000..8e76a8b384ba --- /dev/null +++ b/drivers/firmware/efi/libstub/screen_info.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/efi.h> +#include <asm/efi.h> + +#include "efistub.h" + +/* + * There are two ways of populating the core kernel's struct screen_info via the stub: + * - using a configuration table, like below, which relies on the EFI init code + * to locate the table and copy the contents; + * - by linking directly to the core kernel's copy of the global symbol. + * + * The latter is preferred because it makes the EFIFB earlycon available very + * early, but it only works if the EFI stub is part of the core kernel image + * itself. The zboot decompressor can only use the configuration table + * approach. + * + * In order to support both methods from the same build of the EFI stub + * library, provide this dummy global definition of struct screen_info. If it + * is required to satisfy a link dependency, it means we need to override the + * __weak alloc and free methods with the ones below, and those will be pulled + * in as well. + */ +struct screen_info screen_info; + +static efi_guid_t screen_info_guid = LINUX_EFI_SCREEN_INFO_TABLE_GUID; + +struct screen_info *alloc_screen_info(void) +{ + struct screen_info *si; + efi_status_t status; + + status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, + sizeof(*si), (void **)&si); + + if (status != EFI_SUCCESS) + return NULL; + + status = efi_bs_call(install_configuration_table, + &screen_info_guid, si); + if (status == EFI_SUCCESS) + return si; + + efi_bs_call(free_pool, si); + return NULL; +} + +void free_screen_info(struct screen_info *si) +{ + if (!si) + return; + + efi_bs_call(install_configuration_table, &screen_info_guid, NULL); + efi_bs_call(free_pool, si); +} |