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