diff options
Diffstat (limited to 'drivers/firmware/efi/libstub/efi-stub.c')
| -rw-r--r-- | drivers/firmware/efi/libstub/efi-stub.c | 118 | 
1 files changed, 50 insertions, 68 deletions
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c index f515394cce6e..cf474f0dd261 100644 --- a/drivers/firmware/efi/libstub/efi-stub.c +++ b/drivers/firmware/efi/libstub/efi-stub.c @@ -10,7 +10,6 @@   */  #include <linux/efi.h> -#include <linux/libfdt.h>  #include <asm/efi.h>  #include "efistub.h" @@ -40,16 +39,22 @@  #ifdef CONFIG_ARM64  # define EFI_RT_VIRTUAL_LIMIT	DEFAULT_MAP_WINDOW_64 -#elif defined(CONFIG_RISCV) +#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)  # define EFI_RT_VIRTUAL_LIMIT	TASK_SIZE_MIN -#else +#else /* Only if TASK_SIZE is a constant */  # define EFI_RT_VIRTUAL_LIMIT	TASK_SIZE  #endif -static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; -static bool flat_va_mapping; +/* + * Some architectures map the EFI regions into the kernel's linear map using a + * fixed offset. + */ +#ifndef EFI_RT_VIRTUAL_OFFSET +#define EFI_RT_VIRTUAL_OFFSET	0 +#endif -const efi_system_table_t *efi_system_table; +static u64 virtmap_base = EFI_RT_VIRTUAL_BASE; +static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);  static struct screen_info *setup_graphics(void)  { @@ -124,16 +129,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,  	unsigned long image_addr;  	unsigned long image_size = 0;  	/* addr/point and size pairs for memory management*/ -	unsigned long initrd_addr = 0; -	unsigned long initrd_size = 0; -	unsigned long fdt_addr = 0;  /* Original DTB */ -	unsigned long fdt_size = 0;  	char *cmdline_ptr = NULL;  	int cmdline_size = 0;  	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;  	unsigned long reserve_addr = 0;  	unsigned long reserve_size = 0; -	enum efi_secureboot_mode secure_boot;  	struct screen_info *si;  	efi_properties_table_t *prop_tbl; @@ -154,8 +154,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,  	 * information about the running image, such as size and the command  	 * line.  	 */ -	status = efi_system_table->boottime->handle_protocol(handle, -					&loaded_image_proto, (void *)&image); +	status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, +			     (void *)&image);  	if (status != EFI_SUCCESS) {  		efi_err("Failed to get loaded image protocol\n");  		goto fail; @@ -209,40 +209,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,  	/* Ask the firmware to clear memory on unclean shutdown */  	efi_enable_reset_attack_mitigation(); -	secure_boot = efi_get_secureboot(); - -	/* -	 * Unauthenticated device tree data is a security hazard, so ignore -	 * 'dtb=' unless UEFI Secure Boot is disabled.  We assume that secure -	 * boot is enabled if we can't determine its state. -	 */ -	if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) || -	     secure_boot != efi_secureboot_mode_disabled) { -		if (strstr(cmdline_ptr, "dtb=")) -			efi_err("Ignoring DTB from command line.\n"); -	} else { -		status = efi_load_dtb(image, &fdt_addr, &fdt_size); - -		if (status != EFI_SUCCESS) { -			efi_err("Failed to load device tree!\n"); -			goto fail_free_image; -		} -	} - -	if (fdt_addr) { -		efi_info("Using DTB from command line\n"); -	} else { -		/* Look for a device tree configuration table entry. */ -		fdt_addr = (uintptr_t)get_fdt(&fdt_size); -		if (fdt_addr) -			efi_info("Using DTB from configuration table\n"); -	} - -	if (!fdt_addr) -		efi_info("Generating empty DTB\n"); - -	efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX, -			efi_get_max_initrd_addr(image_addr)); +	efi_load_initrd(image, ULONG_MAX, efi_get_max_initrd_addr(image_addr), +			NULL);  	efi_random_get_seed(); @@ -254,8 +222,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,  	 * The easiest way to achieve that is to simply use a 1:1 mapping.  	 */  	prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID); -	flat_va_mapping = prop_tbl && -			  (prop_tbl->memory_protection_attribute & +	flat_va_mapping |= prop_tbl && +			   (prop_tbl->memory_protection_attribute &  			   EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);  	/* force efi_novamap if SetVirtualAddressMap() is unsupported */ @@ -284,25 +252,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,  	install_memreserve_table(); -	status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr, -						initrd_addr, initrd_size, -						cmdline_ptr, fdt_addr, fdt_size); -	if (status != EFI_SUCCESS) -		goto fail_free_initrd; - -	if (IS_ENABLED(CONFIG_ARM)) -		efi_handle_post_ebs_state(); - -	efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr)); -	/* not reached */ - -fail_free_initrd: -	efi_err("Failed to update FDT and exit boot services\n"); +	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr); -	efi_free(initrd_size, initrd_addr); -	efi_free(fdt_size, fdt_addr); - -fail_free_image:  	efi_free(image_size, image_addr);  	efi_free(reserve_size, reserve_addr);  fail_free_screeninfo: @@ -314,6 +265,35 @@ fail:  }  /* + * efi_allocate_virtmap() - create a pool allocation for the virtmap + * + * Create an allocation that is of sufficient size to hold all the memory + * descriptors that will be passed to SetVirtualAddressMap() to inform the + * firmware about the virtual mapping that will be used under the OS to call + * into the firmware. + */ +efi_status_t efi_alloc_virtmap(efi_memory_desc_t **virtmap, +			       unsigned long *desc_size, u32 *desc_ver) +{ +	unsigned long size, mmap_key; +	efi_status_t status; + +	/* +	 * Use the size of the current memory map as an upper bound for the +	 * size of the buffer we need to pass to SetVirtualAddressMap() to +	 * cover all EFI_MEMORY_RUNTIME regions. +	 */ +	size = 0; +	status = efi_bs_call(get_memory_map, &size, NULL, &mmap_key, desc_size, +			     desc_ver); +	if (status != EFI_BUFFER_TOO_SMALL) +		return EFI_LOAD_ERROR; + +	return efi_bs_call(allocate_pool, EFI_LOADER_DATA, size, +			   (void **)virtmap); +} + +/*   * efi_get_virtmap() - create a virtual mapping for the EFI memory map   *   * This function populates the virt_addr fields of all memory region descriptors @@ -328,6 +308,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,  	efi_memory_desc_t *in, *out = runtime_map;  	int l; +	*count = 0; +  	for (l = 0; l < map_size; l += desc_size) {  		u64 paddr, size; @@ -338,7 +320,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,  		paddr = in->phys_addr;  		size = in->num_pages * EFI_PAGE_SIZE; -		in->virt_addr = in->phys_addr; +		in->virt_addr = in->phys_addr + EFI_RT_VIRTUAL_OFFSET;  		if (efi_novamap) {  			continue;  		}  |