diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index 211f0e2e55e2..a9d206e35fc1 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h @@ -38,7 +38,7 @@ PROVIDE(__efistub__end = _end); PROVIDE(__efistub___inittext_end = __inittext_end); PROVIDE(__efistub__edata = _edata); #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB) -PROVIDE(__efistub_screen_info = screen_info); +PROVIDE(__efistub_sysfb_primary_display = sysfb_primary_display); #endif PROVIDE(__efistub__ctype = _ctype); diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c index 52c21c895318..69dd83f8082f 100644 --- a/arch/loongarch/kernel/efi.c +++ b/arch/loongarch/kernel/efi.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -72,30 +72,31 @@ 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 screen_info screen_info __section(".data"); -EXPORT_SYMBOL_GPL(screen_info); +struct sysfb_display_info sysfb_primary_display __section(".data"); +EXPORT_SYMBOL_GPL(sysfb_primary_display); #endif -static void __init init_screen_info(void) +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; } - screen_info = *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(&screen_info), screen_info.lfb_size); + memblock_reserve(__screen_info_lfb_base(&sysfb_primary_display.screen), + sysfb_primary_display.screen.lfb_size); } void __init efi_init(void) @@ -129,7 +130,7 @@ void __init efi_init(void) set_bit(EFI_CONFIG_TABLES, &efi.flags); if (IS_ENABLED(CONFIG_EFI_EARLYCON) || IS_ENABLED(CONFIG_SYSFB)) - init_screen_info(); + init_primary_display(); if (boot_memmap == EFI_INVALID_TABLE_ADDR) return; diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h index 41ddcf56d21c..e557ebd46c2b 100644 --- a/arch/loongarch/kernel/image-vars.h +++ b/arch/loongarch/kernel/image-vars.h @@ -12,7 +12,7 @@ __efistub_kernel_entry = kernel_entry; __efistub_kernel_asize = kernel_asize; __efistub_kernel_fsize = kernel_fsize; #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB) -__efistub_screen_info = screen_info; +__efistub_sysfb_primary_display = sysfb_primary_display; #endif #endif diff --git a/arch/riscv/kernel/image-vars.h b/arch/riscv/kernel/image-vars.h index 3df30dd1c458..3bd9d06a8b8f 100644 --- a/arch/riscv/kernel/image-vars.h +++ b/arch/riscv/kernel/image-vars.h @@ -29,7 +29,7 @@ __efistub__end = _end; __efistub__edata = _edata; __efistub___init_text_end = __init_text_end; #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB) -__efistub_screen_info = screen_info; +__efistub_sysfb_primary_display = sysfb_primary_display; #endif #endif diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index c3244ac680d1..7508d0ccc740 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -303,7 +304,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch; /* Copying screen_info will do? */ - memcpy(¶ms->screen_info, &screen_info, sizeof(struct screen_info)); + memcpy(¶ms->screen_info, &sysfb_primary_display.screen, + sizeof(sysfb_primary_display.screen)); /* Fill in memsize later */ params->screen_info.ext_mem_k = 0; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 1b2edd07a3e1..d9bfe2032cd9 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -211,12 +212,9 @@ arch_initcall(init_x86_sysctl); /* * Setup options */ -struct screen_info screen_info; -EXPORT_SYMBOL(screen_info); -#if defined(CONFIG_FIRMWARE_EDID) -struct edid_info edid_info; -EXPORT_SYMBOL_GPL(edid_info); -#endif + +struct sysfb_display_info sysfb_primary_display; +EXPORT_SYMBOL(sysfb_primary_display); extern int root_mountflags; @@ -526,9 +524,9 @@ static void __init parse_setup_data(void) static void __init parse_boot_params(void) { ROOT_DEV = old_decode_dev(boot_params.hdr.root_dev); - screen_info = boot_params.screen_info; + sysfb_primary_display.screen = boot_params.screen_info; #if defined(CONFIG_FIRMWARE_EDID) - edid_info = boot_params.edid_info; + sysfb_primary_display.edid = boot_params.edid_info; #endif #ifdef CONFIG_X86_32 apm_info.bios = boot_params.apm_bios_info; @@ -1254,7 +1252,7 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY)) - vgacon_register_screen(&screen_info); + vgacon_register_screen(&sysfb_primary_display.screen); #endif #endif x86_init.oem.banner(); diff --git a/arch/x86/video/video-common.c b/arch/x86/video/video-common.c index e0aeee99bc99..152789f00fcd 100644 --- a/arch/x86/video/video-common.c +++ b/arch/x86/video/video-common.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -29,7 +29,7 @@ EXPORT_SYMBOL(pgprot_framebuffer); bool video_is_primary_device(struct device *dev) { #ifdef CONFIG_SCREEN_INFO - struct screen_info *si = &screen_info; + struct screen_info *si = &sysfb_primary_display.screen; struct resource res[SCREEN_INFO_MAX_RESOURCES]; ssize_t i, numres; #endif diff --git a/drivers/firmware/efi/earlycon.c b/drivers/firmware/efi/earlycon.c index d18a1a5de144..3d060d59968c 100644 --- a/drivers/firmware/efi/earlycon.c +++ b/drivers/firmware/efi/earlycon.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include @@ -32,12 +32,13 @@ static void *efi_fb; */ static int __init efi_earlycon_remap_fb(void) { + const struct screen_info *si = &sysfb_primary_display.screen; + /* bail if there is no bootconsole or it was unregistered already */ if (!earlycon_console || !console_is_registered(earlycon_console)) return 0; - efi_fb = memremap(fb_base, screen_info.lfb_size, - fb_wb ? MEMREMAP_WB : MEMREMAP_WC); + efi_fb = memremap(fb_base, si->lfb_size, fb_wb ? MEMREMAP_WB : MEMREMAP_WC); return efi_fb ? 0 : -ENOMEM; } @@ -71,12 +72,12 @@ static __ref void efi_earlycon_unmap(void *addr, unsigned long len) early_memunmap(addr, len); } -static void efi_earlycon_clear_scanline(unsigned int y) +static void efi_earlycon_clear_scanline(unsigned int y, const struct screen_info *si) { unsigned long *dst; u16 len; - len = screen_info.lfb_linelength; + len = si->lfb_linelength; dst = efi_earlycon_map(y*len, len); if (!dst) return; @@ -85,7 +86,7 @@ static void efi_earlycon_clear_scanline(unsigned int y) efi_earlycon_unmap(dst, len); } -static void efi_earlycon_scroll_up(void) +static void efi_earlycon_scroll_up(const struct screen_info *si) { unsigned long *dst, *src; u16 maxlen = 0; @@ -99,8 +100,8 @@ static void efi_earlycon_scroll_up(void) } maxlen *= 4; - len = screen_info.lfb_linelength; - height = screen_info.lfb_height; + len = si->lfb_linelength; + height = si->lfb_height; for (i = 0; i < height - font->height; i++) { dst = efi_earlycon_map(i*len, len); @@ -120,7 +121,8 @@ static void efi_earlycon_scroll_up(void) } } -static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h) +static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h, + const struct screen_info *si) { const u32 color_black = 0x00000000; const u32 color_white = 0x00ffffff; @@ -145,13 +147,12 @@ static void efi_earlycon_write_char(u32 *dst, unsigned char c, unsigned int h) static void efi_earlycon_write(struct console *con, const char *str, unsigned int num) { - struct screen_info *si; + const struct screen_info *si = &sysfb_primary_display.screen; u32 cur_efi_x = efi_x; unsigned int len; const char *s; void *dst; - si = &screen_info; len = si->lfb_linelength; while (num) { @@ -174,7 +175,7 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) x = efi_x; while (n-- > 0) { - efi_earlycon_write_char(dst + x*4, *s, h); + efi_earlycon_write_char(dst + x * 4, *s, h, si); x += font->width; s++; } @@ -207,10 +208,10 @@ efi_earlycon_write(struct console *con, const char *str, unsigned int num) cur_line_y = (cur_line_y + 1) % max_line_y; efi_y -= font->height; - efi_earlycon_scroll_up(); + efi_earlycon_scroll_up(si); for (i = 0; i < font->height; i++) - efi_earlycon_clear_scanline(efi_y + i); + efi_earlycon_clear_scanline(efi_y + i, si); } } } @@ -226,22 +227,21 @@ void __init efi_earlycon_reprobe(void) static int __init efi_earlycon_setup(struct earlycon_device *device, const char *opt) { - struct screen_info *si; + const struct screen_info *si = &sysfb_primary_display.screen; u16 xres, yres; u32 i; fb_wb = opt && !strcmp(opt, "ram"); - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) { + if (si->orig_video_isVGA != VIDEO_TYPE_EFI) { fb_probed = true; return -ENODEV; } - fb_base = screen_info.lfb_base; - if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) - fb_base |= (u64)screen_info.ext_lfb_base << 32; + fb_base = si->lfb_base; + if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) + fb_base |= (u64)si->ext_lfb_base << 32; - si = &screen_info; xres = si->lfb_width; yres = si->lfb_height; @@ -266,7 +266,7 @@ static int __init efi_earlycon_setup(struct earlycon_device *device, efi_y -= font->height; for (i = 0; i < (yres - efi_y) / font->height; i++) - efi_earlycon_scroll_up(); + efi_earlycon_scroll_up(si); device->con->write = efi_earlycon_write; earlycon_console = device->con; diff --git a/drivers/firmware/efi/efi-init.c b/drivers/firmware/efi/efi-init.c index a65c2d5b9e7b..432301dce76f 100644 --- a/drivers/firmware/efi/efi-init.c +++ b/drivers/firmware/efi/efi-init.c @@ -19,11 +19,11 @@ #include #include #include -#include +#include #include -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) { @@ -57,31 +57,31 @@ static phys_addr_t __init efi_to_phys(unsigned long addr) extern __weak const efi_config_table_type_t efi_arch_tables[]; /* - * x86 defines its own screen_info and uses it even without EFI, - * everything else can get it from here. + * x86 defines its own instance of sysfb_primary_display and uses + * it even without EFI, everything else can get them from here. */ #if !defined(CONFIG_X86) && (defined(CONFIG_SYSFB) || defined(CONFIG_EFI_EARLYCON)) -struct screen_info screen_info __section(".data"); -EXPORT_SYMBOL_GPL(screen_info); +struct sysfb_display_info sysfb_primary_display __section(".data"); +EXPORT_SYMBOL_GPL(sysfb_primary_display); #endif -static void __init init_screen_info(void) +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; } - screen_info = *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(screen_info.lfb_base)) - memblock_mark_nomap(screen_info.lfb_base, - screen_info.lfb_size); + if (memblock_is_map_memory(sysfb_primary_display.screen.lfb_base)) + memblock_mark_nomap(sysfb_primary_display.screen.lfb_base, + sysfb_primary_display.screen.lfb_size); if (IS_ENABLED(CONFIG_EFI_EARLYCON)) efi_earlycon_reprobe(); @@ -274,5 +274,5 @@ void __init efi_init(void) if (IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_SYSFB) || IS_ENABLED(CONFIG_EFI_EARLYCON)) - init_screen_info(); + init_primary_display(); } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 17b5f3415465..111e87a618e5 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -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), @@ -642,7 +642,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 {}, }; 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 a6c049835190..aa85e910fe59 100644 --- a/drivers/firmware/efi/libstub/efi-stub-entry.c +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c @@ -1,23 +1,28 @@ // SPDX-License-Identifier: GPL-2.0-only #include -#include +#include #include #include "efistub.h" -static unsigned long screen_info_offset; +static unsigned long kernel_image_offset; -struct screen_info *alloc_screen_info(void) +static void *kernel_image_addr(void *addr) +{ + return addr + kernel_image_offset; +} + +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)) - return (void *)&screen_info + screen_info_offset; + return kernel_image_addr(&sysfb_primary_display); return NULL; } @@ -73,7 +78,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, return status; } - screen_info_offset = image_addr - (unsigned long)image->image_base; + kernel_image_offset = image_addr - (unsigned long)image->image_base; status = efi_stub_common(handle, image, image_addr, cmdline_ptr); 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 -#include +#include #include #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; } 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 +#include + +#include + +#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 -#include - -#include - -#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 diff --git a/drivers/firmware/efi/sysfb_efi.c b/drivers/firmware/efi/sysfb_efi.c index 1e509595ac03..4c3986ddcd54 100644 --- a/drivers/firmware/efi/sysfb_efi.c +++ b/drivers/firmware/efi/sysfb_efi.c @@ -92,7 +92,7 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt) }) #ifdef CONFIG_EFI -static int __init efifb_set_system(const struct dmi_system_id *id) +static int __init efifb_set_system(struct screen_info *si, const struct dmi_system_id *id) { struct efifb_dmi_info *info = id->driver_data; @@ -101,14 +101,14 @@ static int __init efifb_set_system(const struct dmi_system_id *id) return 0; /* Trust the bootloader over the DMI tables */ - if (screen_info.lfb_base == 0) { + if (si->lfb_base == 0) { #if defined(CONFIG_PCI) struct pci_dev *dev = NULL; int found_bar = 0; #endif if (info->base) { - screen_info.lfb_base = choose_value(info->base, - screen_info.lfb_base, OVERRIDE_BASE, + si->lfb_base = choose_value(info->base, + si->lfb_base, OVERRIDE_BASE, info->flags); #if defined(CONFIG_PCI) @@ -135,49 +135,53 @@ static int __init efifb_set_system(const struct dmi_system_id *id) start = pci_resource_start(dev, i); end = pci_resource_end(dev, i); - if (screen_info.lfb_base >= start && - screen_info.lfb_base < end) { + if (si->lfb_base >= start && si->lfb_base < end) { found_bar = 1; break; } } } if (!found_bar) - screen_info.lfb_base = 0; + si->lfb_base = 0; #endif } } - if (screen_info.lfb_base) { - screen_info.lfb_linelength = choose_value(info->stride, - screen_info.lfb_linelength, OVERRIDE_STRIDE, + if (si->lfb_base) { + si->lfb_linelength = choose_value(info->stride, + si->lfb_linelength, OVERRIDE_STRIDE, info->flags); - screen_info.lfb_width = choose_value(info->width, - screen_info.lfb_width, OVERRIDE_WIDTH, + si->lfb_width = choose_value(info->width, + si->lfb_width, OVERRIDE_WIDTH, info->flags); - screen_info.lfb_height = choose_value(info->height, - screen_info.lfb_height, OVERRIDE_HEIGHT, + si->lfb_height = choose_value(info->height, + si->lfb_height, OVERRIDE_HEIGHT, info->flags); - if (screen_info.orig_video_isVGA == 0) - screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; + if (si->orig_video_isVGA == 0) + si->orig_video_isVGA = VIDEO_TYPE_EFI; } else { - screen_info.lfb_linelength = 0; - screen_info.lfb_width = 0; - screen_info.lfb_height = 0; - screen_info.orig_video_isVGA = 0; + si->lfb_linelength = 0; + si->lfb_width = 0; + si->lfb_height = 0; + si->orig_video_isVGA = 0; return 0; } printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x " "(%dx%d, stride %d)\n", id->ident, - screen_info.lfb_base, screen_info.lfb_width, - screen_info.lfb_height, screen_info.lfb_linelength); + si->lfb_base, si->lfb_width, + si->lfb_height, si->lfb_linelength); return 1; } +static int __init efifb_set_system_callback(const struct dmi_system_id *id) +{ + return efifb_set_system(&sysfb_primary_display.screen, id); +} + #define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \ { \ - efifb_set_system, \ + efifb_set_system_callback, \ name, \ { \ DMI_MATCH(DMI_BIOS_VENDOR, vendor), \ @@ -231,6 +235,44 @@ static const struct dmi_system_id efifb_dmi_system_table[] __initconst = { {}, }; +static int __init efifb_swap_width_height(const struct dmi_system_id *id) +{ + struct screen_info *si = &sysfb_primary_display.screen; + u32 bpp = __screen_info_lfb_bits_per_pixel(si); + + swap(si->lfb_width, si->lfb_height); + si->lfb_linelength = bpp * si->lfb_width / BITS_PER_BYTE; + + return 1; +} + +struct efifb_mode_fixup { + unsigned int width; + unsigned int height; + unsigned int linelength; +}; + +static int __init +efifb_check_and_swap_width_height(const struct dmi_system_id *id) +{ + const struct efifb_mode_fixup *data = id->driver_data; + struct screen_info *si = &sysfb_primary_display.screen; + + if (data->width == si->lfb_width && data->height == si->lfb_height) { + swap(si->lfb_width, si->lfb_height); + si->lfb_linelength = data->linelength; + si->lfb_size = data->linelength * data->width; + } + + return 1; +} + +static const struct efifb_mode_fixup efifb_steamdeck_mode_fixup __initconst = { + .width = 1280, + .height = 800, + .linelength = 3328, +}; + /* * Some devices have a portrait LCD but advertise a landscape resolution (and * pitch). We simply swap width and height for these devices so that we can @@ -248,6 +290,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"), DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1HCN44WW"), }, + .callback = efifb_swap_width_height, }, { /* Lenovo MIIX 320-10ICR with 800x1280 portrait screen */ @@ -256,6 +299,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), }, + .callback = efifb_swap_width_height, }, { /* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */ @@ -264,6 +308,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad D330-10IGM"), }, + .callback = efifb_swap_width_height, }, { /* Lenovo IdeaPad Duet 3 10IGL5 with 1200x1920 portrait screen */ @@ -272,6 +317,7 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "IdeaPad Duet 3 10IGL5"), }, + .callback = efifb_swap_width_height, }, { /* Lenovo Yoga Book X91F / X91L */ @@ -280,16 +326,38 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = { /* Non exact match to match F + L versions */ DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"), }, + .callback = efifb_swap_width_height, + }, + { + /* Valve Steam Deck (Jupiter) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"), + }, + .callback = efifb_check_and_swap_width_height, + .driver_data = (void *)&efifb_steamdeck_mode_fixup, + }, + { + /* Valve Steam Deck (Galileo) */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Valve"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Galileo"), + DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "1"), + }, + .callback = efifb_check_and_swap_width_height, + .driver_data = (void *)&efifb_steamdeck_mode_fixup, }, {}, }; -static bool efifb_overlaps_pci_range(const struct of_pci_range *range) +static bool efifb_overlaps_pci_range(const struct screen_info *si, + const struct of_pci_range *range) { - u64 fb_base = screen_info.lfb_base; + u64 fb_base = si->lfb_base; - if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) - fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32; + if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) + fb_base |= (u64)(unsigned long)si->ext_lfb_base << 32; return fb_base >= range->cpu_addr && fb_base < (range->cpu_addr + range->size); @@ -311,7 +379,7 @@ static struct device_node *find_pci_overlap_node(void) } for_each_of_pci_range(&parser, &range) - if (efifb_overlaps_pci_range(&range)) + if (efifb_overlaps_pci_range(&sysfb_primary_display.screen, &range)) return np; } return NULL; @@ -349,25 +417,19 @@ static const struct fwnode_operations efifb_fwnode_ops = { static struct fwnode_handle efifb_fwnode; -__init void sysfb_apply_efi_quirks(void) +__init void sysfb_apply_efi_quirks(struct screen_info *si) { - if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || - !(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS)) + if (si->orig_video_isVGA != VIDEO_TYPE_EFI || + !(si->capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS)) dmi_check_system(efifb_dmi_system_table); - if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && - dmi_check_system(efifb_dmi_swap_width_height)) { - u16 temp = screen_info.lfb_width; - - screen_info.lfb_width = screen_info.lfb_height; - screen_info.lfb_height = temp; - screen_info.lfb_linelength = 4 * screen_info.lfb_width; - } + if (si->orig_video_isVGA == VIDEO_TYPE_EFI) + dmi_check_system(efifb_dmi_swap_width_height); } -__init void sysfb_set_efifb_fwnode(struct platform_device *pd) +__init void sysfb_set_efifb_fwnode(const struct screen_info *si, struct platform_device *pd) { - if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) { + if (si->orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) { fwnode_init(&efifb_fwnode, &efifb_fwnode_ops); pd->dev.fwnode = &efifb_fwnode; } diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 889e5b05c739..8833582c1883 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -66,7 +66,7 @@ static bool sysfb_unregister(void) */ void sysfb_disable(struct device *dev) { - struct screen_info *si = &screen_info; + struct screen_info *si = &sysfb_primary_display.screen; struct device *parent; mutex_lock(&disable_lock); @@ -92,7 +92,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable); */ bool sysfb_handles_screen_info(void) { - const struct screen_info *si = &screen_info; + const struct screen_info *si = &sysfb_primary_display.screen; return !!screen_info_video_type(si); } @@ -141,7 +141,8 @@ static struct device *sysfb_parent_dev(const struct screen_info *si) static __init int sysfb_init(void) { - struct screen_info *si = &screen_info; + struct sysfb_display_info *dpy = &sysfb_primary_display; + struct screen_info *si = &dpy->screen; struct device *parent; unsigned int type; struct simplefb_platform_data mode; @@ -155,7 +156,7 @@ static __init int sysfb_init(void) if (disabled) goto unlock_mutex; - sysfb_apply_efi_quirks(); + sysfb_apply_efi_quirks(si); parent = sysfb_parent_dev(si); if (IS_ERR(parent)) { @@ -200,9 +201,9 @@ static __init int sysfb_init(void) pd->dev.parent = parent; - sysfb_set_efifb_fwnode(pd); + sysfb_set_efifb_fwnode(si, pd); - ret = platform_device_add_data(pd, si, sizeof(*si)); + ret = platform_device_add_data(pd, dpy, sizeof(*dpy)); if (ret) goto err; diff --git a/drivers/firmware/sysfb_simplefb.c b/drivers/firmware/sysfb_simplefb.c index 592d8a644619..71f542e37732 100644 --- a/drivers/firmware/sysfb_simplefb.c +++ b/drivers/firmware/sysfb_simplefb.c @@ -117,7 +117,7 @@ __init struct platform_device *sysfb_create_simplefb(const struct screen_info *s pd->dev.parent = parent; - sysfb_set_efifb_fwnode(pd); + sysfb_set_efifb_fwnode(si, pd); ret = platform_device_add_resources(pd, &res, 1); if (ret) diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c index 1b683d55d6ea..50e0aeef709c 100644 --- a/drivers/gpu/drm/sysfb/efidrm.c +++ b/drivers/gpu/drm/sysfb/efidrm.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -24,7 +24,6 @@ #include #include -#include