Commit 732ea9db authored by Ard Biesheuvel's avatar Ard Biesheuvel

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: default avatarArd Biesheuvel <ardb@kernel.org>
parent 06064800
...@@ -43,9 +43,6 @@ void efi_virtmap_unload(void); ...@@ -43,9 +43,6 @@ void efi_virtmap_unload(void);
/* arch specific definitions used by the stub code */ /* arch specific definitions used by the stub code */
struct screen_info *alloc_screen_info(void);
void free_screen_info(struct screen_info *si);
/* /*
* A reasonable upper bound for the uncompressed kernel size is 32 MBytes, * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
* so we will reserve that amount of memory. We have no easy way to tell what * so we will reserve that amount of memory. We have no easy way to tell what
......
...@@ -75,38 +75,13 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) ...@@ -75,38 +75,13 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
return 0; return 0;
} }
static unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata cpu_state_table = EFI_INVALID_TABLE_ADDR;
const efi_config_table_type_t efi_arch_tables[] __initconst = { const efi_config_table_type_t efi_arch_tables[] __initconst = {
{LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_table},
{LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table}, {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table},
{} {}
}; };
static void __init load_screen_info_table(void)
{
struct screen_info *si;
if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
si = early_memremap_ro(screen_info_table, sizeof(*si));
if (!si) {
pr_err("Could not map screen_info config table\n");
return;
}
screen_info = *si;
early_memunmap(si, sizeof(*si));
/* dummycon on ARM needs non-zero values for columns/lines */
screen_info.orig_video_cols = 80;
screen_info.orig_video_lines = 25;
if (memblock_is_map_memory(screen_info.lfb_base))
memblock_mark_nomap(screen_info.lfb_base,
screen_info.lfb_size);
}
}
static void __init load_cpu_state_table(void) static void __init load_cpu_state_table(void)
{ {
if (cpu_state_table != EFI_INVALID_TABLE_ADDR) { if (cpu_state_table != EFI_INVALID_TABLE_ADDR) {
...@@ -145,7 +120,11 @@ void __init arm_efi_init(void) ...@@ -145,7 +120,11 @@ void __init arm_efi_init(void)
{ {
efi_init(); efi_init();
load_screen_info_table(); if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
/* dummycon on ARM needs non-zero values for columns/lines */
screen_info.orig_video_cols = 80;
screen_info.orig_video_lines = 25;
}
/* ARM does not permit early mappings to persist across paging_init() */ /* ARM does not permit early mappings to persist across paging_init() */
efi_memmap_unmap(); efi_memmap_unmap();
......
...@@ -84,12 +84,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) ...@@ -84,12 +84,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1)); return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));
} }
#define alloc_screen_info(x...) &screen_info
static inline void free_screen_info(struct screen_info *si)
{
}
#define EFI_ALLOC_ALIGN SZ_64K #define EFI_ALLOC_ALIGN SZ_64K
/* /*
......
...@@ -19,15 +19,6 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt); ...@@ -19,15 +19,6 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
#define EFI_ALLOC_ALIGN SZ_64K #define EFI_ALLOC_ALIGN SZ_64K
#define EFI_RT_VIRTUAL_OFFSET CSR_DMW0_BASE #define EFI_RT_VIRTUAL_OFFSET CSR_DMW0_BASE
static inline struct screen_info *alloc_screen_info(void)
{
return &screen_info;
}
static inline void free_screen_info(struct screen_info *si)
{
}
static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
{ {
return ULONG_MAX; return ULONG_MAX;
......
...@@ -52,6 +52,27 @@ void __init efi_runtime_init(void) ...@@ -52,6 +52,27 @@ void __init efi_runtime_init(void)
set_bit(EFI_RUNTIME_SERVICES, &efi.flags); set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
} }
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
static void __init init_screen_info(void)
{
struct screen_info *si;
if (screen_info_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");
return;
}
screen_info = *si;
memset(si, 0, sizeof(*si));
early_memunmap(si, sizeof(*si));
memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
}
void __init efi_init(void) void __init efi_init(void)
{ {
int size; int size;
...@@ -80,8 +101,7 @@ void __init efi_init(void) ...@@ -80,8 +101,7 @@ void __init efi_init(void)
set_bit(EFI_CONFIG_TABLES, &efi.flags); set_bit(EFI_CONFIG_TABLES, &efi.flags);
if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) init_screen_info();
memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
if (boot_memmap == EFI_INVALID_TABLE_ADDR) if (boot_memmap == EFI_INVALID_TABLE_ADDR)
return; return;
......
...@@ -31,12 +31,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) ...@@ -31,12 +31,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
return ULONG_MAX; return ULONG_MAX;
} }
#define alloc_screen_info(x...) (&screen_info)
static inline void free_screen_info(struct screen_info *si)
{
}
void efi_virtmap_load(void); void efi_virtmap_load(void);
void efi_virtmap_unload(void); void efi_virtmap_unload(void);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <asm/efi.h> #include <asm/efi.h>
unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR;
static int __init is_memory(efi_memory_desc_t *md) static int __init is_memory(efi_memory_desc_t *md)
{ {
if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC)) if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
...@@ -55,9 +57,22 @@ extern __weak const efi_config_table_type_t efi_arch_tables[]; ...@@ -55,9 +57,22 @@ extern __weak const efi_config_table_type_t efi_arch_tables[];
static void __init init_screen_info(void) static void __init init_screen_info(void)
{ {
if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && struct screen_info *si;
memblock_is_map_memory(screen_info.lfb_base))
memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); 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");
return;
}
screen_info = *si;
memset(si, 0, sizeof(*si));
early_memunmap(si, sizeof(*si));
if (memblock_is_map_memory(screen_info.lfb_base))
memblock_mark_nomap(screen_info.lfb_base,
screen_info.lfb_size);
}
} }
static int __init uefi_init(u64 efi_system_table) static int __init uefi_init(u64 efi_system_table)
......
...@@ -58,6 +58,8 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR; ...@@ -58,6 +58,8 @@ static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR; static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
extern unsigned long screen_info_table;
struct mm_struct efi_mm = { struct mm_struct efi_mm = {
.mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock), .mm_mt = MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock),
.mm_users = ATOMIC_INIT(2), .mm_users = ATOMIC_INIT(2),
...@@ -546,6 +548,9 @@ static const efi_config_table_type_t common_tables[] __initconst = { ...@@ -546,6 +548,9 @@ static const efi_config_table_type_t common_tables[] __initconst = {
#endif #endif
#ifdef CONFIG_EFI_COCO_SECRET #ifdef CONFIG_EFI_COCO_SECRET
{LINUX_EFI_COCO_SECRET_AREA_GUID, &efi.coco_secret, "CocoSecret" }, {LINUX_EFI_COCO_SECRET_AREA_GUID, &efi.coco_secret, "CocoSecret" },
#endif
#ifdef CONFIG_EFI_GENERIC_STUB
{LINUX_EFI_SCREEN_INFO_TABLE_GUID, &screen_info_table },
#endif #endif
{}, {},
}; };
......
...@@ -81,7 +81,8 @@ lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \ ...@@ -81,7 +81,8 @@ lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \
$(obj)/lib-%.o: $(srctree)/lib/%.c FORCE $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
$(call if_changed_rule,cc_o_c) $(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_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o lib-$(CONFIG_ARM64) += arm64-stub.o arm64-entry.o
......
...@@ -76,43 +76,6 @@ void efi_handle_post_ebs_state(void) ...@@ -76,43 +76,6 @@ void efi_handle_post_ebs_state(void)
&efi_entry_state->sctlr_after_ebs); &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, efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size, unsigned long *image_size,
unsigned long *reserve_addr, unsigned long *reserve_addr,
......
...@@ -47,6 +47,15 @@ ...@@ -47,6 +47,15 @@
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0); 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) static struct screen_info *setup_graphics(void)
{ {
efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
......
...@@ -975,4 +975,7 @@ efi_enable_reset_attack_mitigation(void) { } ...@@ -975,4 +975,7 @@ efi_enable_reset_attack_mitigation(void) { }
void efi_retrieve_tpm2_eventlog(void); void efi_retrieve_tpm2_eventlog(void);
struct screen_info *alloc_screen_info(void);
void free_screen_info(struct screen_info *si);
#endif #endif
// 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);
}
...@@ -403,7 +403,7 @@ void efi_native_runtime_setup(void); ...@@ -403,7 +403,7 @@ void efi_native_runtime_setup(void);
* structure that was populated by the stub based on the GOP protocol instance * structure that was populated by the stub based on the GOP protocol instance
* associated with ConOut * associated with ConOut
*/ */
#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) #define LINUX_EFI_SCREEN_INFO_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_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_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) #define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment