forked from mirrors/linux
		
	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: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
		
							parent
							
								
									06064800d9
								
							
						
					
					
						commit
						732ea9db9d
					
				
					 14 changed files with 121 additions and 94 deletions
				
			
		|  | @ -43,9 +43,6 @@ void efi_virtmap_unload(void); | |||
| 
 | ||||
| /* 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, | ||||
|  * 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) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static unsigned long __initdata screen_info_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 = { | ||||
| 	{LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_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) | ||||
| { | ||||
| 	if (cpu_state_table != EFI_INVALID_TABLE_ADDR) { | ||||
|  | @ -145,7 +120,11 @@ void __init arm_efi_init(void) | |||
| { | ||||
| 	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() */ | ||||
| 	efi_memmap_unmap(); | ||||
|  |  | |||
|  | @ -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)); | ||||
| } | ||||
| 
 | ||||
| #define alloc_screen_info(x...)		&screen_info | ||||
| 
 | ||||
| static inline void free_screen_info(struct screen_info *si) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #define EFI_ALLOC_ALIGN		SZ_64K | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -19,15 +19,6 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt); | |||
| #define EFI_ALLOC_ALIGN		SZ_64K | ||||
| #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) | ||||
| { | ||||
| 	return ULONG_MAX; | ||||
|  |  | |||
|  | @ -52,6 +52,27 @@ void __init efi_runtime_init(void) | |||
| 	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) | ||||
| { | ||||
| 	int size; | ||||
|  | @ -80,8 +101,7 @@ void __init efi_init(void) | |||
| 
 | ||||
| 	set_bit(EFI_CONFIG_TABLES, &efi.flags); | ||||
| 
 | ||||
| 	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) | ||||
| 		memblock_reserve(screen_info.lfb_base, screen_info.lfb_size); | ||||
| 	init_screen_info(); | ||||
| 
 | ||||
| 	if (boot_memmap == EFI_INVALID_TABLE_ADDR) | ||||
| 		return; | ||||
|  |  | |||
|  | @ -31,12 +31,6 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr) | |||
| 	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_unload(void); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,8 @@ | |||
| 
 | ||||
| #include <asm/efi.h> | ||||
| 
 | ||||
| unsigned long __initdata screen_info_table = EFI_INVALID_TABLE_ADDR; | ||||
| 
 | ||||
| static int __init is_memory(efi_memory_desc_t *md) | ||||
| { | ||||
| 	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[]; | |||
| 
 | ||||
| static void __init init_screen_info(void) | ||||
| { | ||||
| 	if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && | ||||
| 	    memblock_is_map_memory(screen_info.lfb_base)) | ||||
| 		memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size); | ||||
| 	struct screen_info *si; | ||||
| 
 | ||||
| 	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) | ||||
|  |  | |||
|  | @ -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 initrd = EFI_INVALID_TABLE_ADDR; | ||||
| 
 | ||||
| extern unsigned long screen_info_table; | ||||
| 
 | ||||
| struct mm_struct efi_mm = { | ||||
| 	.mm_mt			= MTREE_INIT_EXT(mm_mt, MM_MT_FLAGS, efi_mm.mmap_lock), | ||||
| 	.mm_users		= ATOMIC_INIT(2), | ||||
|  | @ -546,6 +548,9 @@ static const efi_config_table_type_t common_tables[] __initconst = { | |||
| #endif | ||||
| #ifdef CONFIG_EFI_COCO_SECRET | ||||
| 	{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 | ||||
| 	{}, | ||||
| }; | ||||
|  |  | |||
|  | @ -81,7 +81,8 @@ lib-$(CONFIG_EFI_PARAMS_FROM_FDT) += fdt.o \ | |||
| $(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 | ||||
| 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_ARM64)		+= arm64-stub.o arm64-entry.o | ||||
|  |  | |||
|  | @ -76,43 +76,6 @@ void efi_handle_post_ebs_state(void) | |||
| 		      &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, | ||||
| 				 unsigned long *image_size, | ||||
| 				 unsigned long *reserve_addr, | ||||
|  |  | |||
|  | @ -47,6 +47,15 @@ | |||
| static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; | ||||
| 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) | ||||
| { | ||||
| 	efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; | ||||
|  |  | |||
|  | @ -975,4 +975,7 @@ efi_enable_reset_attack_mitigation(void) { } | |||
| 
 | ||||
| void efi_retrieve_tpm2_eventlog(void); | ||||
| 
 | ||||
| struct screen_info *alloc_screen_info(void); | ||||
| void free_screen_info(struct screen_info *si); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										56
									
								
								drivers/firmware/efi/libstub/screen_info.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								drivers/firmware/efi/libstub/screen_info.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| // 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); | |||
|  * structure that was populated by the stub based on the GOP protocol instance | ||||
|  * 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_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…
	
		Reference in a new issue
	
	 Ard Biesheuvel
						Ard Biesheuvel