18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * EFI stub implementation that is shared by arm and arm64 architectures.
48c2ecf20Sopenharmony_ci * This should be #included by the EFI stub implementation files.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2013,2014 Linaro Limited
78c2ecf20Sopenharmony_ci *     Roy Franz <roy.franz@linaro.org
88c2ecf20Sopenharmony_ci * Copyright (C) 2013 Red Hat, Inc.
98c2ecf20Sopenharmony_ci *     Mark Salter <msalter@redhat.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/efi.h>
138c2ecf20Sopenharmony_ci#include <asm/efi.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "efistub.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * This is the base address at which to start allocating virtual memory ranges
198c2ecf20Sopenharmony_ci * for UEFI Runtime Services.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * For ARM/ARM64:
228c2ecf20Sopenharmony_ci * This is in the low TTBR0 range so that we can use
238c2ecf20Sopenharmony_ci * any allocation we choose, and eliminate the risk of a conflict after kexec.
248c2ecf20Sopenharmony_ci * The value chosen is the largest non-zero power of 2 suitable for this purpose
258c2ecf20Sopenharmony_ci * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
268c2ecf20Sopenharmony_ci * be mapped efficiently.
278c2ecf20Sopenharmony_ci * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
288c2ecf20Sopenharmony_ci * map everything below 1 GB. (512 MB is a reasonable upper bound for the
298c2ecf20Sopenharmony_ci * entire footprint of the UEFI runtime services memory regions)
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * For RISC-V:
328c2ecf20Sopenharmony_ci * There is no specific reason for which, this address (512MB) can't be used
338c2ecf20Sopenharmony_ci * EFI runtime virtual address for RISC-V. It also helps to use EFI runtime
348c2ecf20Sopenharmony_ci * services on both RV32/RV64. Keep the same runtime virtual address for RISC-V
358c2ecf20Sopenharmony_ci * as well to minimize the code churn.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci#define EFI_RT_VIRTUAL_BASE	SZ_512M
388c2ecf20Sopenharmony_ci#define EFI_RT_VIRTUAL_SIZE	SZ_512M
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64
418c2ecf20Sopenharmony_ci# define EFI_RT_VIRTUAL_LIMIT	DEFAULT_MAP_WINDOW_64
428c2ecf20Sopenharmony_ci#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
438c2ecf20Sopenharmony_ci# define EFI_RT_VIRTUAL_LIMIT	TASK_SIZE_MIN
448c2ecf20Sopenharmony_ci#else
458c2ecf20Sopenharmony_ci# define EFI_RT_VIRTUAL_LIMIT	TASK_SIZE
468c2ecf20Sopenharmony_ci#endif
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#ifndef EFI_RT_VIRTUAL_OFFSET
498c2ecf20Sopenharmony_ci#define EFI_RT_VIRTUAL_OFFSET	0
508c2ecf20Sopenharmony_ci#endif
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
538c2ecf20Sopenharmony_cistatic bool flat_va_mapping = !!EFI_RT_VIRTUAL_OFFSET;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciconst efi_system_table_t *efi_system_table;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic struct screen_info *setup_graphics(void)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
608c2ecf20Sopenharmony_ci	efi_status_t status;
618c2ecf20Sopenharmony_ci	unsigned long size;
628c2ecf20Sopenharmony_ci	void **gop_handle = NULL;
638c2ecf20Sopenharmony_ci	struct screen_info *si = NULL;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	size = 0;
668c2ecf20Sopenharmony_ci	status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
678c2ecf20Sopenharmony_ci			     &gop_proto, NULL, &size, gop_handle);
688c2ecf20Sopenharmony_ci	if (status == EFI_BUFFER_TOO_SMALL) {
698c2ecf20Sopenharmony_ci		si = alloc_screen_info();
708c2ecf20Sopenharmony_ci		if (!si)
718c2ecf20Sopenharmony_ci			return NULL;
728c2ecf20Sopenharmony_ci		status = efi_setup_gop(si, &gop_proto, size);
738c2ecf20Sopenharmony_ci		if (status != EFI_SUCCESS) {
748c2ecf20Sopenharmony_ci			free_screen_info(si);
758c2ecf20Sopenharmony_ci			return NULL;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	return si;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void install_memreserve_table(void)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct linux_efi_memreserve *rsv;
848c2ecf20Sopenharmony_ci	efi_guid_t memreserve_table_guid = LINUX_EFI_MEMRESERVE_TABLE_GUID;
858c2ecf20Sopenharmony_ci	efi_status_t status;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*rsv),
888c2ecf20Sopenharmony_ci			     (void **)&rsv);
898c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS) {
908c2ecf20Sopenharmony_ci		efi_err("Failed to allocate memreserve entry!\n");
918c2ecf20Sopenharmony_ci		return;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	rsv->next = 0;
958c2ecf20Sopenharmony_ci	rsv->size = 0;
968c2ecf20Sopenharmony_ci	atomic_set(&rsv->count, 0);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	status = efi_bs_call(install_configuration_table,
998c2ecf20Sopenharmony_ci			     &memreserve_table_guid, rsv);
1008c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS)
1018c2ecf20Sopenharmony_ci		efi_err("Failed to install memreserve config table!\n");
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic u32 get_supported_rt_services(void)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	const efi_rt_properties_table_t *rt_prop_table;
1078c2ecf20Sopenharmony_ci	u32 supported = EFI_RT_SUPPORTED_ALL;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	rt_prop_table = get_efi_config_table(EFI_RT_PROPERTIES_TABLE_GUID);
1108c2ecf20Sopenharmony_ci	if (rt_prop_table)
1118c2ecf20Sopenharmony_ci		supported &= rt_prop_table->runtime_services_supported;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return supported;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/*
1178c2ecf20Sopenharmony_ci * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
1188c2ecf20Sopenharmony_ci * that is described in the PE/COFF header.  Most of the code is the same
1198c2ecf20Sopenharmony_ci * for both archictectures, with the arch-specific code provided in the
1208c2ecf20Sopenharmony_ci * handle_kernel_image() function.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ciefi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
1238c2ecf20Sopenharmony_ci				   efi_system_table_t *sys_table_arg)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	efi_loaded_image_t *image;
1268c2ecf20Sopenharmony_ci	efi_status_t status;
1278c2ecf20Sopenharmony_ci	unsigned long image_addr;
1288c2ecf20Sopenharmony_ci	unsigned long image_size = 0;
1298c2ecf20Sopenharmony_ci	/* addr/point and size pairs for memory management*/
1308c2ecf20Sopenharmony_ci	char *cmdline_ptr = NULL;
1318c2ecf20Sopenharmony_ci	int cmdline_size = 0;
1328c2ecf20Sopenharmony_ci	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
1338c2ecf20Sopenharmony_ci	unsigned long reserve_addr = 0;
1348c2ecf20Sopenharmony_ci	unsigned long reserve_size = 0;
1358c2ecf20Sopenharmony_ci	struct screen_info *si;
1368c2ecf20Sopenharmony_ci	efi_properties_table_t *prop_tbl;
1378c2ecf20Sopenharmony_ci	unsigned long max_addr;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	efi_system_table = sys_table_arg;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Check if we were booted by the EFI firmware */
1428c2ecf20Sopenharmony_ci	if (efi_system_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
1438c2ecf20Sopenharmony_ci		status = EFI_INVALID_PARAMETER;
1448c2ecf20Sopenharmony_ci		goto fail;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	status = check_platform_features();
1488c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS)
1498c2ecf20Sopenharmony_ci		goto fail;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/*
1528c2ecf20Sopenharmony_ci	 * Get a handle to the loaded image protocol.  This is used to get
1538c2ecf20Sopenharmony_ci	 * information about the running image, such as size and the command
1548c2ecf20Sopenharmony_ci	 * line.
1558c2ecf20Sopenharmony_ci	 */
1568c2ecf20Sopenharmony_ci	status = efi_system_table->boottime->handle_protocol(handle,
1578c2ecf20Sopenharmony_ci					&loaded_image_proto, (void *)&image);
1588c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS) {
1598c2ecf20Sopenharmony_ci		efi_err("Failed to get loaded image protocol\n");
1608c2ecf20Sopenharmony_ci		goto fail;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/*
1648c2ecf20Sopenharmony_ci	 * Get the command line from EFI, using the LOADED_IMAGE
1658c2ecf20Sopenharmony_ci	 * protocol. We are going to copy the command line into the
1668c2ecf20Sopenharmony_ci	 * device tree, so this can be allocated anywhere.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
1698c2ecf20Sopenharmony_ci	if (!cmdline_ptr) {
1708c2ecf20Sopenharmony_ci		efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
1718c2ecf20Sopenharmony_ci		status = EFI_OUT_OF_RESOURCES;
1728c2ecf20Sopenharmony_ci		goto fail;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) ||
1768c2ecf20Sopenharmony_ci	    IS_ENABLED(CONFIG_CMDLINE_FORCE) ||
1778c2ecf20Sopenharmony_ci	    cmdline_size == 0) {
1788c2ecf20Sopenharmony_ci		status = efi_parse_options(CONFIG_CMDLINE);
1798c2ecf20Sopenharmony_ci		if (status != EFI_SUCCESS) {
1808c2ecf20Sopenharmony_ci			efi_err("Failed to parse options\n");
1818c2ecf20Sopenharmony_ci			goto fail_free_cmdline;
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline_size > 0) {
1868c2ecf20Sopenharmony_ci		status = efi_parse_options(cmdline_ptr);
1878c2ecf20Sopenharmony_ci		if (status != EFI_SUCCESS) {
1888c2ecf20Sopenharmony_ci			efi_err("Failed to parse options\n");
1898c2ecf20Sopenharmony_ci			goto fail_free_cmdline;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	efi_info("Booting Linux Kernel...\n");
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	si = setup_graphics();
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	status = handle_kernel_image(&image_addr, &image_size,
1988c2ecf20Sopenharmony_ci				     &reserve_addr,
1998c2ecf20Sopenharmony_ci				     &reserve_size,
2008c2ecf20Sopenharmony_ci				     image);
2018c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS) {
2028c2ecf20Sopenharmony_ci		efi_err("Failed to relocate kernel\n");
2038c2ecf20Sopenharmony_ci		goto fail_free_screeninfo;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	efi_retrieve_tpm2_eventlog();
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Ask the firmware to clear memory on unclean shutdown */
2098c2ecf20Sopenharmony_ci	efi_enable_reset_attack_mitigation();
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (!efi_noinitrd) {
2128c2ecf20Sopenharmony_ci		max_addr = efi_get_max_initrd_addr(image_addr);
2138c2ecf20Sopenharmony_ci		efi_load_initrd(image, ULONG_MAX, efi_get_max_initrd_addr(image_addr),
2148c2ecf20Sopenharmony_ci				NULL);
2158c2ecf20Sopenharmony_ci		if (status != EFI_SUCCESS)
2168c2ecf20Sopenharmony_ci			efi_err("Failed to load initrd!\n");
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	efi_random_get_seed();
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * If the NX PE data feature is enabled in the properties table, we
2238c2ecf20Sopenharmony_ci	 * should take care not to create a virtual mapping that changes the
2248c2ecf20Sopenharmony_ci	 * relative placement of runtime services code and data regions, as
2258c2ecf20Sopenharmony_ci	 * they may belong to the same PE/COFF executable image in memory.
2268c2ecf20Sopenharmony_ci	 * The easiest way to achieve that is to simply use a 1:1 mapping.
2278c2ecf20Sopenharmony_ci	 */
2288c2ecf20Sopenharmony_ci	prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
2298c2ecf20Sopenharmony_ci	flat_va_mapping |= prop_tbl &&
2308c2ecf20Sopenharmony_ci			   (prop_tbl->memory_protection_attribute &
2318c2ecf20Sopenharmony_ci			   EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* force efi_novamap if SetVirtualAddressMap() is unsupported */
2348c2ecf20Sopenharmony_ci	efi_novamap |= !(get_supported_rt_services() &
2358c2ecf20Sopenharmony_ci			 EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* hibernation expects the runtime regions to stay in the same place */
2388c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_HIBERNATION) && !efi_nokaslr && !flat_va_mapping) {
2398c2ecf20Sopenharmony_ci		/*
2408c2ecf20Sopenharmony_ci		 * Randomize the base of the UEFI runtime services region.
2418c2ecf20Sopenharmony_ci		 * Preserve the 2 MB alignment of the region by taking a
2428c2ecf20Sopenharmony_ci		 * shift of 21 bit positions into account when scaling
2438c2ecf20Sopenharmony_ci		 * the headroom value using a 32-bit random value.
2448c2ecf20Sopenharmony_ci		 */
2458c2ecf20Sopenharmony_ci		static const u64 headroom = EFI_RT_VIRTUAL_LIMIT -
2468c2ecf20Sopenharmony_ci					    EFI_RT_VIRTUAL_BASE -
2478c2ecf20Sopenharmony_ci					    EFI_RT_VIRTUAL_SIZE;
2488c2ecf20Sopenharmony_ci		u32 rnd;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		status = efi_get_random_bytes(sizeof(rnd), (u8 *)&rnd);
2518c2ecf20Sopenharmony_ci		if (status == EFI_SUCCESS) {
2528c2ecf20Sopenharmony_ci			virtmap_base = EFI_RT_VIRTUAL_BASE +
2538c2ecf20Sopenharmony_ci				       (((headroom >> 21) * rnd) >> (32 - 21));
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	install_memreserve_table();
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	efi_free(image_size, image_addr);
2628c2ecf20Sopenharmony_ci	efi_free(reserve_size, reserve_addr);
2638c2ecf20Sopenharmony_cifail_free_screeninfo:
2648c2ecf20Sopenharmony_ci	free_screen_info(si);
2658c2ecf20Sopenharmony_cifail_free_cmdline:
2668c2ecf20Sopenharmony_ci	efi_bs_call(free_pool, cmdline_ptr);
2678c2ecf20Sopenharmony_cifail:
2688c2ecf20Sopenharmony_ci	return status;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci/*
2728c2ecf20Sopenharmony_ci * efi_allocate_virtmap() - create a pool allocation for the virtmap
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci * Create an allocation that is of sufficient size to hold all the memory
2758c2ecf20Sopenharmony_ci * descriptors that will be passed to SetVirtualAddressMap() to inform the
2768c2ecf20Sopenharmony_ci * firmware about the virtual mapping that will be used under the OS to call
2778c2ecf20Sopenharmony_ci * into the firmware.
2788c2ecf20Sopenharmony_ci */
2798c2ecf20Sopenharmony_ciefi_status_t efi_alloc_virtmap(efi_memory_desc_t **virtmap,
2808c2ecf20Sopenharmony_ci			       unsigned long *desc_size, u32 *desc_ver)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	unsigned long size, mmap_key;
2838c2ecf20Sopenharmony_ci	efi_status_t status;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/*
2868c2ecf20Sopenharmony_ci	 * Use the size of the current memory map as an upper bound for the
2878c2ecf20Sopenharmony_ci	 * size of the buffer we need to pass to SetVirtualAddressMap() to
2888c2ecf20Sopenharmony_ci	 * cover all EFI_MEMORY_RUNTIME regions.
2898c2ecf20Sopenharmony_ci	 */
2908c2ecf20Sopenharmony_ci	size = 0;
2918c2ecf20Sopenharmony_ci	status = efi_bs_call(get_memory_map, &size, NULL, &mmap_key, desc_size,
2928c2ecf20Sopenharmony_ci			     desc_ver);
2938c2ecf20Sopenharmony_ci	if (status != EFI_BUFFER_TOO_SMALL)
2948c2ecf20Sopenharmony_ci		return EFI_LOAD_ERROR;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return efi_bs_call(allocate_pool, EFI_LOADER_DATA, size,
2978c2ecf20Sopenharmony_ci			   (void **)virtmap);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci/*
3018c2ecf20Sopenharmony_ci * efi_get_virtmap() - create a virtual mapping for the EFI memory map
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * This function populates the virt_addr fields of all memory region descriptors
3048c2ecf20Sopenharmony_ci * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
3058c2ecf20Sopenharmony_ci * are also copied to @runtime_map, and their total count is returned in @count.
3068c2ecf20Sopenharmony_ci */
3078c2ecf20Sopenharmony_civoid efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
3088c2ecf20Sopenharmony_ci		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
3098c2ecf20Sopenharmony_ci		     int *count)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	u64 efi_virt_base = virtmap_base;
3128c2ecf20Sopenharmony_ci	efi_memory_desc_t *in, *out = runtime_map;
3138c2ecf20Sopenharmony_ci	int l;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	*count = 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	for (l = 0; l < map_size; l += desc_size) {
3188c2ecf20Sopenharmony_ci		u64 paddr, size;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci		in = (void *)memory_map + l;
3218c2ecf20Sopenharmony_ci		if (!(in->attribute & EFI_MEMORY_RUNTIME))
3228c2ecf20Sopenharmony_ci			continue;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		paddr = in->phys_addr;
3258c2ecf20Sopenharmony_ci		size = in->num_pages * EFI_PAGE_SIZE;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		in->virt_addr = in->phys_addr + EFI_RT_VIRTUAL_OFFSET;
3288c2ecf20Sopenharmony_ci		if (efi_novamap) {
3298c2ecf20Sopenharmony_ci			continue;
3308c2ecf20Sopenharmony_ci		}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		/*
3338c2ecf20Sopenharmony_ci		 * Make the mapping compatible with 64k pages: this allows
3348c2ecf20Sopenharmony_ci		 * a 4k page size kernel to kexec a 64k page size kernel and
3358c2ecf20Sopenharmony_ci		 * vice versa.
3368c2ecf20Sopenharmony_ci		 */
3378c2ecf20Sopenharmony_ci		if (!flat_va_mapping) {
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci			paddr = round_down(in->phys_addr, SZ_64K);
3408c2ecf20Sopenharmony_ci			size += in->phys_addr - paddr;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci			/*
3438c2ecf20Sopenharmony_ci			 * Avoid wasting memory on PTEs by choosing a virtual
3448c2ecf20Sopenharmony_ci			 * base that is compatible with section mappings if this
3458c2ecf20Sopenharmony_ci			 * region has the appropriate size and physical
3468c2ecf20Sopenharmony_ci			 * alignment. (Sections are 2 MB on 4k granule kernels)
3478c2ecf20Sopenharmony_ci			 */
3488c2ecf20Sopenharmony_ci			if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
3498c2ecf20Sopenharmony_ci				efi_virt_base = round_up(efi_virt_base, SZ_2M);
3508c2ecf20Sopenharmony_ci			else
3518c2ecf20Sopenharmony_ci				efi_virt_base = round_up(efi_virt_base, SZ_64K);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci			in->virt_addr += efi_virt_base - paddr;
3548c2ecf20Sopenharmony_ci			efi_virt_base += size;
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		memcpy(out, in, desc_size);
3588c2ecf20Sopenharmony_ci		out = (void *)out + desc_size;
3598c2ecf20Sopenharmony_ci		++*count;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci}
362