mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
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>
This commit is contained in:
parent
4fcae63588
commit
c5a8f13f1e
12 changed files with 124 additions and 109 deletions
|
|
@ -72,7 +72,7 @@ bool efi_poweroff_required(void)
|
|||
(acpi_gbl_reduced_hardware || acpi_no_s5);
|
||||
}
|
||||
|
||||
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
|
||||
unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
|
||||
|
||||
#if defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)
|
||||
struct sysfb_display_info sysfb_primary_display __section(".data");
|
||||
|
|
@ -81,19 +81,19 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
|
|||
|
||||
static void __init init_primary_display(void)
|
||||
{
|
||||
struct screen_info *si;
|
||||
struct sysfb_display_info *dpy;
|
||||
|
||||
if (screen_info_table == EFI_INVALID_TABLE_ADDR)
|
||||
if (primary_display_table == EFI_INVALID_TABLE_ADDR)
|
||||
return;
|
||||
|
||||
si = early_memremap(screen_info_table, sizeof(*si));
|
||||
if (!si) {
|
||||
pr_err("Could not map screen_info config table\n");
|
||||
dpy = early_memremap(primary_display_table, sizeof(*dpy));
|
||||
if (!dpy) {
|
||||
pr_err("Could not map primary_display config table\n");
|
||||
return;
|
||||
}
|
||||
sysfb_primary_display.screen = *si;
|
||||
memset(si, 0, sizeof(*si));
|
||||
early_memunmap(si, sizeof(*si));
|
||||
sysfb_primary_display = *dpy;
|
||||
memset(dpy, 0, sizeof(*dpy));
|
||||
early_memunmap(dpy, sizeof(*dpy));
|
||||
|
||||
memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen),
|
||||
sysfb_primary_display.screen.lfb_size);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <asm/efi.h>
|
||||
|
||||
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
|
||||
unsigned long __initdata primary_display_table = EFI_INVALID_TABLE_ADDR;
|
||||
|
||||
static int __init is_memory(efi_memory_desc_t *md)
|
||||
{
|
||||
|
|
@ -67,17 +67,17 @@ EXPORT_SYMBOL_GPL(sysfb_primary_display);
|
|||
|
||||
static void __init init_primary_display(void)
|
||||
{
|
||||
struct screen_info *si;
|
||||
struct sysfb_display_info *dpy;
|
||||
|
||||
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");
|
||||
if (primary_display_table != EFI_INVALID_TABLE_ADDR) {
|
||||
dpy = early_memremap(primary_display_table, sizeof(*dpy));
|
||||
if (!dpy) {
|
||||
pr_err("Could not map primary_display config table\n");
|
||||
return;
|
||||
}
|
||||
sysfb_primary_display.screen = *si;
|
||||
memset(si, 0, sizeof(*si));
|
||||
early_memunmap(si, sizeof(*si));
|
||||
sysfb_primary_display = *dpy;
|
||||
memset(dpy, 0, sizeof(*dpy));
|
||||
early_memunmap(dpy, sizeof(*dpy));
|
||||
|
||||
if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base))
|
||||
memblock_mark_nomap(sysfb_primary_display.screen.lfb_base,
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ 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;
|
||||
extern unsigned long primary_display_table;
|
||||
|
||||
struct mm_struct efi_mm = {
|
||||
.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 = {
|
|||
{LINUX_EFI_UNACCEPTED_MEM_TABLE_GUID, &efi.unaccepted, "Unaccepted" },
|
||||
#endif
|
||||
#ifdef CONFIG_EFI_GENERIC_STUB
|
||||
{LINUX_EFI_SCREEN_INFO_TABLE_GUID, &screen_info_table },
|
||||
{LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID, &primary_display_table },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 sysfb_display_info *setup_primary_display(void)
|
||||
{
|
||||
}
|
||||
struct sysfb_display_info *dpy;
|
||||
struct screen_info *screen = NULL;
|
||||
struct edid_info *edid = NULL;
|
||||
efi_status_t status;
|
||||
|
||||
static struct screen_info *setup_graphics(void)
|
||||
{
|
||||
struct screen_info *si, tmp = {};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
56
drivers/firmware/efi/libstub/primary_display.c
Normal file
56
drivers/firmware/efi/libstub/primary_display.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -63,11 +63,13 @@ endif # HAS_IOMEM
|
|||
|
||||
config FIRMWARE_EDID
|
||||
bool "Enable firmware EDID"
|
||||
depends on X86
|
||||
depends on EFI_GENERIC_STUB || X86
|
||||
help
|
||||
This enables access to the EDID transferred from the firmware.
|
||||
On x86, this is from the VESA BIOS. DRM display drivers will
|
||||
be able to export the information to userspace.
|
||||
On EFI systems, the EDID comes from the same device as the
|
||||
primary GOP. On x86 with BIOS, it comes from the VESA BIOS.
|
||||
DRM display drivers will be able to export the information
|
||||
to userspace.
|
||||
|
||||
Also enable this if DDC/I2C transfers do not work for your driver
|
||||
and if you are using nvidiafb, i810fb or savagefb.
|
||||
|
|
|
|||
|
|
@ -406,11 +406,12 @@ void efi_native_runtime_setup(void);
|
|||
#define EFI_CC_FINAL_EVENTS_TABLE_GUID EFI_GUID(0xdd4a4648, 0x2de7, 0x4665, 0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4, 0x46)
|
||||
|
||||
/*
|
||||
* This GUID is used to pass to the kernel proper the struct screen_info
|
||||
* structure that was populated by the stub based on the GOP protocol instance
|
||||
* associated with ConOut
|
||||
* This GUIDs are used to pass to the kernel proper the primary
|
||||
* display that has been populated by the stub based on the GOP
|
||||
* instance associated with ConOut.
|
||||
*/
|
||||
#define LINUX_EFI_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
|
||||
#define LINUX_EFI_PRIMARY_DISPLAY_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
|
||||
|
||||
#define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989, 0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2)
|
||||
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
|
||||
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue