Skip to content

Commit c5a8f13

Browse files
tdzardbiesheuvel
authored andcommitted
efi: Support EDID information
In the EFI config table, rename LINUX_EFI_SCREEN_INFO_TABLE_GUID to LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID. Read sysfb_primary_display from the entry. In addition to the screen_info, the entry now also contains EDID information. In libstub, replace struct screen_info with struct sysfb_display_info from the kernel's sysfb_primary_display and rename functions accordingly. Transfer it to the runtime kernel using the kernel's global state or the LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID config-table entry. With CONFIG_FIRMWARE_EDID=y, libstub now transfers the GOP device's EDID information to the kernel. If CONFIG_FIRMWARE_EDID=n, EDID information is disabled. Make the Kconfig symbol CONFIG_FIRMWARE_EDID available with EFI. Setting the value to 'n' disables EDID support. Also rename screen_info.c to primary_display.c and adapt the contained comment according to the changes. Link: https://lore.kernel.org/all/20251126160854.553077-8-tzimmermann@suse.de/ Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de> [ardb: depend on EFI_GENERIC_STUB not EFI, fix conflicts after dropping the preceding patch from the series] Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 4fcae63 commit c5a8f13

12 files changed

Lines changed: 123 additions & 108 deletions

File tree

arch/loongarch/kernel/efi.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ bool efi_poweroff_required(void)
7272
(acpi_gbl_reduced_hardware || acpi_no_s5);
7373
}
7474

75-
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
75+
unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
7676

7777
#if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
7878
struct sysfb_display_info sysfb_primary_display __section(".data");
@@ -81,19 +81,19 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
8181

8282
static void __init init_primary_display(void)
8383
{
84-
struct screen_info *si;
84+
struct sysfb_display_info *dpy;
8585

86-
if (screen_info_table == EFI_INVALID_TABLE_ADDR)
86+
if (primary_display_table == EFI_INVALID_TABLE_ADDR)
8787
return;
8888

89-
si = early_memremap(screen_info_table, sizeof(*si));
90-
if (!si) {
91-
pr_err("Could not map screen_info config table\n");
89+
dpy = early_memremap(primary_display_table, sizeof(*dpy));
90+
if (!dpy) {
91+
pr_err("Could not map primary_display config table\n");
9292
return;
9393
}
94-
sysfb_primary_display.screen = *si;
95-
memset(si, 0, sizeof(*si));
96-
early_memunmap(si, sizeof(*si));
94+
sysfb_primary_display = *dpy;
95+
memset(dpy, 0, sizeof(*dpy));
96+
early_memunmap(dpy, sizeof(*dpy));
9797

9898
memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
9999
sysfb_primary_display.screen.lfb_size);

drivers/firmware/efi/efi-init.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#include <asm/efi.h>
2525

26-
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
26+
unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
2727

2828
static int __init is_memory(efi_memory_desc_t *md)
2929
{
@@ -67,17 +67,17 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
6767

6868
static void __init init_primary_display(void)
6969
{
70-
struct screen_info *si;
70+
struct sysfb_display_info *dpy;
7171

72-
if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
73-
si = early_memremap(screen_info_table, sizeof(*si));
74-
if (!si) {
75-
pr_err("Could not map screen_info config table\n");
72+
if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
73+
dpy = early_memremap(primary_display_table, sizeof(*dpy));
74+
if (!dpy) {
75+
pr_err("Could not map primary_display config table\n");
7676
return;
7777
}
78-
sysfb_primary_display.screen = *si;
79-
memset(si, 0, sizeof(*si));
80-
early_memunmap(si, sizeof(*si));
78+
sysfb_primary_display = *dpy;
79+
memset(dpy, 0, sizeof(*dpy));
80+
early_memunmap(dpy, sizeof(*dpy));
8181

8282
if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
8383
memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,

drivers/firmware/efi/efi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
6363
static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
6464
static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
6565

66-
extern unsigned long screen_info_table;
66+
extern unsigned long primary_display_table;
6767

6868
struct mm_struct efi_mm = {
6969
.mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock),
@@ -641,7 +641,7 @@ static const efi_config_table_type_t common_tables[] __initconst = {
641641
{LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID, &efi.unaccepted, "Unaccepted" },
642642
#endif
643643
#ifdef CONFIG_EFI_GENERIC_STUB
644-
{LINUX_EFI_SCREEN_INFO_TABLE_GUID, &screen_info_table },
644+
{LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID, &primary_display_table },
645645
#endif
646646
{},
647647
};

drivers/firmware/efi/libstub/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
8080
$(call if_changed_rule,cc_o_c)
8181

8282
lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o \
83-
screen_info.o efi-stub-entry.o
83+
primary_display.o efi-stub-entry.o
8484

8585
lib-$(CONFIG_ARM) += arm32-stub.o
8686
lib-$(CONFIG_ARM64) += kaslr.o arm64.o arm64-stub.o smbios.o

drivers/firmware/efi/libstub/efi-stub-entry.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,15 @@ static void *kernel_image_addr(void *addr)
1414
return addr + kernel_image_offset;
1515
}
1616

17-
struct screen_info *alloc_screen_info(void)
17+
struct sysfb_display_info *alloc_primary_display(void)
1818
{
1919
if (IS_ENABLED(CONFIG_ARM))
20-
return __alloc_screen_info();
20+
return __alloc_primary_display();
2121

2222
if (IS_ENABLED(CONFIG_X86) ||
2323
IS_ENABLED(CONFIG_EFI_EARLYCON) ||
24-
IS_ENABLED(CONFIG_SYSFB)) {
25-
struct sysfb_display_info *dpy = kernel_image_addr(&sysfb_primary_display);
26-
27-
return &dpy->screen;
28-
}
24+
IS_ENABLED(CONFIG_SYSFB))
25+
return kernel_image_addr(&sysfb_primary_display);
2926

3027
return NULL;
3128
}

drivers/firmware/efi/libstub/efi-stub.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111

1212
#include <linux/efi.h>
13-
#include <linux/screen_info.h>
13+
#include <linux/sysfb.h>
1414
#include <asm/efi.h>
1515

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

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

55-
static struct screen_info *setup_graphics(void)
54+
static struct sysfb_display_info *setup_primary_display(void)
5655
{
57-
struct screen_info *si, tmp = {};
56+
struct sysfb_display_info *dpy;
57+
struct screen_info *screen = NULL;
58+
struct edid_info *edid = NULL;
59+
efi_status_t status;
5860

59-
if (efi_setup_graphics(&tmp, NULL) != EFI_SUCCESS)
61+
dpy = alloc_primary_display();
62+
if (!dpy)
6063
return NULL;
64+
screen = &dpy->screen;
65+
#if defined(CONFIG_FIRMWARE_EDID)
66+
edid = &dpy->edid;
67+
#endif
6168

62-
si = alloc_screen_info();
63-
if (!si)
64-
return NULL;
69+
status = efi_setup_graphics(screen, edid);
70+
if (status != EFI_SUCCESS)
71+
goto err_free_primary_display;
6572

66-
*si = tmp;
67-
return si;
73+
return dpy;
74+
75+
err_free_primary_display:
76+
free_primary_display(dpy);
77+
return NULL;
6878
}
6979

7080
static void install_memreserve_table(void)
@@ -145,14 +155,14 @@ efi_status_t efi_stub_common(efi_handle_t handle,
145155
unsigned long image_addr,
146156
char *cmdline_ptr)
147157
{
148-
struct screen_info *si;
158+
struct sysfb_display_info *dpy;
149159
efi_status_t status;
150160

151161
status = check_platform_features();
152162
if (status != EFI_SUCCESS)
153163
return status;
154164

155-
si = setup_graphics();
165+
dpy = setup_primary_display();
156166

157167
efi_retrieve_eventlog();
158168

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

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

175-
free_screen_info(si);
185+
free_primary_display(dpy);
186+
176187
return status;
177188
}
178189

drivers/firmware/efi/libstub/efistub.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
struct edid_info;
3838
struct screen_info;
39+
struct sysfb_display_info;
3940

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

11761177
void efi_retrieve_eventlog(void);
11771178

1178-
struct screen_info *alloc_screen_info(void);
1179-
struct screen_info *__alloc_screen_info(void);
1180-
void free_screen_info(struct screen_info *si);
1179+
struct sysfb_display_info *alloc_primary_display(void);
1180+
struct sysfb_display_info *__alloc_primary_display(void);
1181+
void free_primary_display(struct sysfb_display_info *dpy);
11811182

11821183
void efi_cache_sync_image(unsigned long image_base,
11831184
unsigned long alloc_size);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/efi.h>
4+
#include <linux/sysfb.h>
5+
6+
#include <asm/efi.h>
7+
8+
#include "efistub.h"
9+
10+
/*
11+
* There are two ways of populating the core kernel's sysfb_primary_display
12+
* via the stub:
13+
*
14+
* - using a configuration table, which relies on the EFI init code to
15+
* locate the table and copy the contents; or
16+
*
17+
* - by linking directly to the core kernel's copy of the global symbol.
18+
*
19+
* The latter is preferred because it makes the EFIFB earlycon available very
20+
* early, but it only works if the EFI stub is part of the core kernel image
21+
* itself. The zboot decompressor can only use the configuration table
22+
* approach.
23+
*/
24+
25+
static efi_guid_t primary_display_guid = LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID;
26+
27+
struct sysfb_display_info *__alloc_primary_display(void)
28+
{
29+
struct sysfb_display_info *dpy;
30+
efi_status_t status;
31+
32+
status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY,
33+
sizeof(*dpy), (void **)&dpy);
34+
35+
if (status != EFI_SUCCESS)
36+
return NULL;
37+
38+
memset(dpy, 0, sizeof(*dpy));
39+
40+
status = efi_bs_call(install_configuration_table,
41+
&primary_display_guid, dpy);
42+
if (status == EFI_SUCCESS)
43+
return dpy;
44+
45+
efi_bs_call(free_pool, dpy);
46+
return NULL;
47+
}
48+
49+
void free_primary_display(struct sysfb_display_info *dpy)
50+
{
51+
if (!dpy)
52+
return;
53+
54+
efi_bs_call(install_configuration_table, &primary_display_guid, NULL);
55+
efi_bs_call(free_pool, dpy);
56+
}

drivers/firmware/efi/libstub/screen_info.c

Lines changed: 0 additions & 53 deletions
This file was deleted.

drivers/firmware/efi/libstub/zboot.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ void __weak efi_cache_sync_image(unsigned long image_base,
2626
// executable code loaded into memory to be safe for execution.
2727
}
2828

29-
struct screen_info *alloc_screen_info(void)
29+
struct sysfb_display_info *alloc_primary_display(void)
3030
{
31-
return __alloc_screen_info();
31+
return __alloc_primary_display();
3232
}
3333

3434
asmlinkage efi_status_t __efiapi

0 commit comments

Comments
 (0)