summaryrefslogtreecommitdiff
path: root/drivers/firmware/efi/libstub
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2022-10-11 18:10:39 +0300
committerArd Biesheuvel <ardb@kernel.org>2022-11-09 14:42:02 +0300
commit732ea9db9d8a6a0444d18ed810cccb2428d8766b (patch)
tree186ea3e313ea11d0d5edae397074828c263e98d6 /drivers/firmware/efi/libstub
parent06064800d92a1adac3717e86cc6ba5f98c0ef40e (diff)
downloadlinux-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/libstub')
-rw-r--r--drivers/firmware/efi/libstub/Makefile3
-rw-r--r--drivers/firmware/efi/libstub/arm32-stub.c37
-rw-r--r--drivers/firmware/efi/libstub/efi-stub.c9
-rw-r--r--drivers/firmware/efi/libstub/efistub.h3
-rw-r--r--drivers/firmware/efi/libstub/screen_info.c56
5 files changed, 70 insertions, 38 deletions
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);
+}