[PATCH v2 09/10] efi: libstub: Transfer EDID to kernel

Thomas Zimmermann
2025-11-24T16:51:39Z

Replace struct screen_info with struct sysfb_display_info from the
kernel's sysfb_primary_display and rename functions accordingly.
Transfer the it to the runtime kernel using the kernel's global state
or the config-table entry LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID.

Also rename screen_info.c to primary_display.c and adapt the contained
comment according to the changes.

With CONFIG_FIRMWARE_EDID=y, libstub now transfers the GOP device's
EDID information to the kernel.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
drivers/firmware/efi/libstub/Makefile | 2 +-
drivers/firmware/efi/libstub/efi-stub-entry.c | 11 ++--
drivers/firmware/efi/libstub/efi-stub.c | 41 +++++++++-----
drivers/firmware/efi/libstub/efistub.h | 7 ++-
.../firmware/efi/libstub/primary_display.c | 56 +++++++++++++++++++
drivers/firmware/efi/libstub/screen_info.c | 53 ------------------
drivers/firmware/efi/libstub/zboot.c | 4 +-
7 files changed, 93 insertions(+), 81 deletions(-)
create mode 100644 drivers/firmware/efi/libstub/primary_display.c
delete mode 100644 drivers/firmware/efi/libstub/screen_info.c

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 7d15a85d579f..e386ffd009b7 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -80,7 +80,7 @@ $(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 \
- screen_info.o efi-stub-entry.o
+ primary_display.o efi-stub-entry.o

lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o
diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c
index 401ecbbdf331..aa85e910fe59 100644
--- a/drivers/firmware/efi/libstub/efi-stub-entry.c
+++ b/drivers/firmware/efi/libstub/efi-stub-entry.c
@@ -14,18 +14,15 @@ static void *kernel_image_addr(void *addr)
return addr + kernel_image_offset;
}

-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
{
if (IS_ENABLED(CONFIG_ARM))
- return __alloc_screen_info();
+ return __alloc_primary_display();

if (IS_ENABLED(CONFIG_X86) ||
IS_ENABLED(CONFIG_EFI_EARLYCON) ||
- IS_ENABLED(CONFIG_SYSFB)) {
- struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
-
- return &dpy->screen;
- }
+ IS_ENABLED(CONFIG_SYSFB))
+ return kernel_image_addr(&sysfb_primary_display);

return NULL;
}
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 9cb814c5ba1b..42d6073bcd06 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -10,7 +10,7 @@
*/

#include <linux/efi.h>
-#include <linux/screen_info.h>
+#include <linux/sysfb.h>
#include <asm/efi.h>

#include "efistub.h"
@@ -48,23 +48,33 @@
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);

-void __weak free_screen_info(struct screen_info *si)
-{
-}
+void __weak free_primary_display(struct sysfb_display_info *dpy)
+{ }

-static struct screen_info *setup_graphics(void)
+static struct sysfb_display_info *setup_primary_display(void)
{
- struct screen_info *si, tmp = {};
+ struct sysfb_display_info *dpy;
+ struct screen_info *screen = NULL;
+ struct edid_info *edid = NULL;
+ efi_status_t status;

- if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
+ dpy = alloc_primary_display();
+ if (!dpy)
return NULL;
+ screen = &dpy->screen;
+#if defined(CONFIG_FIRMWARE_EDID)
+ edid = &dpy->edid;
+#endif

- si = alloc_screen_info();
- if (!si)
- return NULL;
+ status = efi_setup_graphics(screen, edid);
+ if (status != EFI_SUCCESS)
+ goto err_free_primary_display;

- *si = tmp;
- return si;
+ return dpy;
+
+err_free_primary_display:
+ free_primary_display(dpy);
+ return NULL;
}

static void install_memreserve_table(void)
@@ -145,14 +155,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
unsigned long image_addr,
char *cmdline_ptr)
{
- struct screen_info *si;
+ struct sysfb_display_info *dpy;
efi_status_t status;

status = check_platform_features();
if (status != EFI_SUCCESS)
return status;

- si = setup_graphics();
+ dpy = setup_primary_display();

efi_retrieve_eventlog();

@@ -172,7 +182,8 @@ efi_status_t efi_stub_common(efi_handle_t handle,

status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);

- free_screen_info(si);
+ free_primary_display(dpy);
+
return status;
}

diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index b2fb0c3fa721..979a21818cc1 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -36,6 +36,7 @@

struct edid_info;
struct screen_info;
+struct sysfb_display_info;

extern bool efi_no5lvl;
extern bool efi_nochunk;
@@ -1175,9 +1176,9 @@ efi_enable_reset_attack_mitigation(void) { }

void efi_retrieve_eventlog(void);

-struct screen_info *alloc_screen_info(void);
-struct screen_info *__alloc_screen_info(void);
-void free_screen_info(struct screen_info *si);
+struct sysfb_display_info *alloc_primary_display(void);
+struct sysfb_display_info *__alloc_primary_display(void);
+void free_primary_display(struct sysfb_display_info *dpy);

void efi_cache_sync_image(unsigned long image_base,
unsigned long alloc_size);
diff --git a/drivers/firmware/efi/libstub/primary_display.c b/drivers/firmware/efi/libstub/primary_display.c
new file mode 100644
index 000000000000..cdaebab26514
--- /dev/null
+++ b/drivers/firmware/efi/libstub/primary_display.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <linux/sysfb.h>
+
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+/*
+ * There are two ways of populating the core kernel's sysfb_primary_display
+ * via the stub:
+ *
+ * - using a configuration table, which relies on the EFI init code to
+ * locate the table and copy the contents; or
+ *
+ * - 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.
+ */
+
+static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
+
+struct sysfb_display_info *__alloc_primary_display(void)
+{
+ struct sysfb_display_info *dpy;
+ efi_status_t status;
+
+ status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
+ sizeof(*dpy), (void **)&dpy);
+
+ if (status != EFI_SUCCESS)
+ return NULL;
+
+ memset(dpy, 0, sizeof(*dpy));
+
+ status = efi_bs_call(install_configuration_table,
+ &primary_display_guid, dpy);
+ if (status == EFI_SUCCESS)
+ return dpy;
+
+ efi_bs_call(free_pool, dpy);
+ return NULL;
+}
+
+void free_primary_display(struct sysfb_display_info *dpy)
+{
+ if (!dpy)
+ return;
+
+ efi_bs_call(install_configuration_table, &primary_display_guid, NULL);
+ efi_bs_call(free_pool, dpy);
+}
diff --git a/drivers/firmware/efi/libstub/screen_info.c b/drivers/firmware/efi/libstub/screen_info.c
deleted file mode 100644
index 5d3a1e32d177..000000000000
--- a/drivers/firmware/efi/libstub/screen_info.c
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <linux/efi.h>
-#include <linux/screen_info.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.
- */
-
-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;
-
- memset(si, 0, sizeof(*si));
-
- 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);
-}
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index c47ace06f010..4b76f74c56da 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -26,9 +26,9 @@ void __weak efi_cache_sync_image(unsigned long image_base,
// executable code loaded into memory to be safe for execution.
}

-struct screen_info *alloc_screen_info(void)
+struct sysfb_display_info *alloc_primary_display(void)
{
- return __alloc_screen_info();
+ return __alloc_primary_display();
}

asmlinkage efi_status_t __efiapi
--
2.51.1