relocate.c (5057B)
1// SPDX-License-Identifier: GPL-2.0 2 3#include <linux/efi.h> 4#include <asm/efi.h> 5 6#include "efistub.h" 7 8/** 9 * efi_low_alloc_above() - allocate pages at or above given address 10 * @size: size of the memory area to allocate 11 * @align: minimum alignment of the allocated memory area. It should 12 * a power of two. 13 * @addr: on exit the address of the allocated memory 14 * @min: minimum address to used for the memory allocation 15 * 16 * Allocate at the lowest possible address that is not below @min as 17 * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at 18 * least EFI_ALLOC_ALIGN. The first allocated page will not below the address 19 * given by @min. 20 * 21 * Return: status code 22 */ 23efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align, 24 unsigned long *addr, unsigned long min) 25{ 26 unsigned long map_size, desc_size, buff_size; 27 efi_memory_desc_t *map; 28 efi_status_t status; 29 unsigned long nr_pages; 30 int i; 31 struct efi_boot_memmap boot_map; 32 33 boot_map.map = ↦ 34 boot_map.map_size = &map_size; 35 boot_map.desc_size = &desc_size; 36 boot_map.desc_ver = NULL; 37 boot_map.key_ptr = NULL; 38 boot_map.buff_size = &buff_size; 39 40 status = efi_get_memory_map(&boot_map); 41 if (status != EFI_SUCCESS) 42 goto fail; 43 44 /* 45 * Enforce minimum alignment that EFI or Linux requires when 46 * requesting a specific address. We are doing page-based (or 47 * larger) allocations, and both the address and size must meet 48 * alignment constraints. 49 */ 50 if (align < EFI_ALLOC_ALIGN) 51 align = EFI_ALLOC_ALIGN; 52 53 size = round_up(size, EFI_ALLOC_ALIGN); 54 nr_pages = size / EFI_PAGE_SIZE; 55 for (i = 0; i < map_size / desc_size; i++) { 56 efi_memory_desc_t *desc; 57 unsigned long m = (unsigned long)map; 58 u64 start, end; 59 60 desc = efi_early_memdesc_ptr(m, desc_size, i); 61 62 if (desc->type != EFI_CONVENTIONAL_MEMORY) 63 continue; 64 65 if (efi_soft_reserve_enabled() && 66 (desc->attribute & EFI_MEMORY_SP)) 67 continue; 68 69 if (desc->num_pages < nr_pages) 70 continue; 71 72 start = desc->phys_addr; 73 end = start + desc->num_pages * EFI_PAGE_SIZE; 74 75 if (start < min) 76 start = min; 77 78 start = round_up(start, align); 79 if ((start + size) > end) 80 continue; 81 82 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, 83 EFI_LOADER_DATA, nr_pages, &start); 84 if (status == EFI_SUCCESS) { 85 *addr = start; 86 break; 87 } 88 } 89 90 if (i == map_size / desc_size) 91 status = EFI_NOT_FOUND; 92 93 efi_bs_call(free_pool, map); 94fail: 95 return status; 96} 97 98/** 99 * efi_relocate_kernel() - copy memory area 100 * @image_addr: pointer to address of memory area to copy 101 * @image_size: size of memory area to copy 102 * @alloc_size: minimum size of memory to allocate, must be greater or 103 * equal to image_size 104 * @preferred_addr: preferred target address 105 * @alignment: minimum alignment of the allocated memory area. It 106 * should be a power of two. 107 * @min_addr: minimum target address 108 * 109 * Copy a memory area to a newly allocated memory area aligned according 110 * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address 111 * is not available, the allocated address will not be below @min_addr. 112 * On exit, @image_addr is updated to the target copy address that was used. 113 * 114 * This function is used to copy the Linux kernel verbatim. It does not apply 115 * any relocation changes. 116 * 117 * Return: status code 118 */ 119efi_status_t efi_relocate_kernel(unsigned long *image_addr, 120 unsigned long image_size, 121 unsigned long alloc_size, 122 unsigned long preferred_addr, 123 unsigned long alignment, 124 unsigned long min_addr) 125{ 126 unsigned long cur_image_addr; 127 unsigned long new_addr = 0; 128 efi_status_t status; 129 unsigned long nr_pages; 130 efi_physical_addr_t efi_addr = preferred_addr; 131 132 if (!image_addr || !image_size || !alloc_size) 133 return EFI_INVALID_PARAMETER; 134 if (alloc_size < image_size) 135 return EFI_INVALID_PARAMETER; 136 137 cur_image_addr = *image_addr; 138 139 /* 140 * The EFI firmware loader could have placed the kernel image 141 * anywhere in memory, but the kernel has restrictions on the 142 * max physical address it can run at. Some architectures 143 * also have a preferred address, so first try to relocate 144 * to the preferred address. If that fails, allocate as low 145 * as possible while respecting the required alignment. 146 */ 147 nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE; 148 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, 149 EFI_LOADER_DATA, nr_pages, &efi_addr); 150 new_addr = efi_addr; 151 /* 152 * If preferred address allocation failed allocate as low as 153 * possible. 154 */ 155 if (status != EFI_SUCCESS) { 156 status = efi_low_alloc_above(alloc_size, alignment, &new_addr, 157 min_addr); 158 } 159 if (status != EFI_SUCCESS) { 160 efi_err("Failed to allocate usable memory for kernel.\n"); 161 return status; 162 } 163 164 /* 165 * We know source/dest won't overlap since both memory ranges 166 * have been allocated by UEFI, so we can safely use memcpy. 167 */ 168 memcpy((void *)new_addr, (void *)cur_image_addr, image_size); 169 170 /* Return the new address of the relocated image. */ 171 *image_addr = new_addr; 172 173 return status; 174}