xref: /openbmc/linux/drivers/firmware/efi/libstub/mem.c (revision eaa6fc67)
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 #define EFI_MMAP_NR_SLACK_SLOTS	8
9 
10 static inline bool mmap_has_headroom(unsigned long buff_size,
11 				     unsigned long map_size,
12 				     unsigned long desc_size)
13 {
14 	unsigned long slack = buff_size - map_size;
15 
16 	return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
17 }
18 
19 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
20 {
21 	efi_memory_desc_t *m = NULL;
22 	efi_status_t status;
23 	unsigned long key;
24 	u32 desc_version;
25 
26 	*map->desc_size =	sizeof(*m);
27 	*map->map_size =	*map->desc_size * 32;
28 	*map->buff_size =	*map->map_size;
29 again:
30 	status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
31 			     *map->map_size, (void **)&m);
32 	if (status != EFI_SUCCESS)
33 		goto fail;
34 
35 	*map->desc_size = 0;
36 	key = 0;
37 	status = efi_bs_call(get_memory_map, map->map_size, m,
38 			     &key, map->desc_size, &desc_version);
39 	if (status == EFI_BUFFER_TOO_SMALL ||
40 	    !mmap_has_headroom(*map->buff_size, *map->map_size,
41 			       *map->desc_size)) {
42 		efi_bs_call(free_pool, m);
43 		/*
44 		 * Make sure there is some entries of headroom so that the
45 		 * buffer can be reused for a new map after allocations are
46 		 * no longer permitted.  Its unlikely that the map will grow to
47 		 * exceed this headroom once we are ready to trigger
48 		 * ExitBootServices()
49 		 */
50 		*map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
51 		*map->buff_size = *map->map_size;
52 		goto again;
53 	}
54 
55 	if (status != EFI_SUCCESS)
56 		efi_bs_call(free_pool, m);
57 
58 	if (map->key_ptr && status == EFI_SUCCESS)
59 		*map->key_ptr = key;
60 	if (map->desc_ver && status == EFI_SUCCESS)
61 		*map->desc_ver = desc_version;
62 
63 fail:
64 	*map->map = m;
65 	return status;
66 }
67 
68 /**
69  * efi_allocate_pages() - Allocate memory pages
70  * @size:	minimum number of bytes to allocate
71  * @addr:	On return the address of the first allocated page. The first
72  *		allocated page has alignment EFI_ALLOC_ALIGN which is an
73  *		architecture dependent multiple of the page size.
74  * @max:	the address that the last allocated memory page shall not
75  *		exceed
76  *
77  * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
78  * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
79  * given by @max.
80  *
81  * Return:	status code
82  */
83 efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
84 				unsigned long max)
85 {
86 	efi_physical_addr_t alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
87 	int slack = EFI_ALLOC_ALIGN / EFI_PAGE_SIZE - 1;
88 	efi_status_t status;
89 
90 	size = round_up(size, EFI_ALLOC_ALIGN);
91 	status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
92 			     EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
93 			     &alloc_addr);
94 	if (status != EFI_SUCCESS)
95 		return status;
96 
97 	*addr = ALIGN((unsigned long)alloc_addr, EFI_ALLOC_ALIGN);
98 
99 	if (slack > 0) {
100 		int l = (alloc_addr % EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
101 
102 		if (l) {
103 			efi_bs_call(free_pages, alloc_addr, slack - l + 1);
104 			slack = l - 1;
105 		}
106 		if (slack)
107 			efi_bs_call(free_pages, *addr + size, slack);
108 	}
109 	return EFI_SUCCESS;
110 }
111 /*
112  * Allocate at the lowest possible address that is not below 'min'.
113  */
114 efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
115 				 unsigned long *addr, unsigned long min)
116 {
117 	unsigned long map_size, desc_size, buff_size;
118 	efi_memory_desc_t *map;
119 	efi_status_t status;
120 	unsigned long nr_pages;
121 	int i;
122 	struct efi_boot_memmap boot_map;
123 
124 	boot_map.map		= &map;
125 	boot_map.map_size	= &map_size;
126 	boot_map.desc_size	= &desc_size;
127 	boot_map.desc_ver	= NULL;
128 	boot_map.key_ptr	= NULL;
129 	boot_map.buff_size	= &buff_size;
130 
131 	status = efi_get_memory_map(&boot_map);
132 	if (status != EFI_SUCCESS)
133 		goto fail;
134 
135 	/*
136 	 * Enforce minimum alignment that EFI or Linux requires when
137 	 * requesting a specific address.  We are doing page-based (or
138 	 * larger) allocations, and both the address and size must meet
139 	 * alignment constraints.
140 	 */
141 	if (align < EFI_ALLOC_ALIGN)
142 		align = EFI_ALLOC_ALIGN;
143 
144 	size = round_up(size, EFI_ALLOC_ALIGN);
145 	nr_pages = size / EFI_PAGE_SIZE;
146 	for (i = 0; i < map_size / desc_size; i++) {
147 		efi_memory_desc_t *desc;
148 		unsigned long m = (unsigned long)map;
149 		u64 start, end;
150 
151 		desc = efi_early_memdesc_ptr(m, desc_size, i);
152 
153 		if (desc->type != EFI_CONVENTIONAL_MEMORY)
154 			continue;
155 
156 		if (efi_soft_reserve_enabled() &&
157 		    (desc->attribute & EFI_MEMORY_SP))
158 			continue;
159 
160 		if (desc->num_pages < nr_pages)
161 			continue;
162 
163 		start = desc->phys_addr;
164 		end = start + desc->num_pages * EFI_PAGE_SIZE;
165 
166 		if (start < min)
167 			start = min;
168 
169 		start = round_up(start, align);
170 		if ((start + size) > end)
171 			continue;
172 
173 		status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
174 				     EFI_LOADER_DATA, nr_pages, &start);
175 		if (status == EFI_SUCCESS) {
176 			*addr = start;
177 			break;
178 		}
179 	}
180 
181 	if (i == map_size / desc_size)
182 		status = EFI_NOT_FOUND;
183 
184 	efi_bs_call(free_pool, map);
185 fail:
186 	return status;
187 }
188 
189 void efi_free(unsigned long size, unsigned long addr)
190 {
191 	unsigned long nr_pages;
192 
193 	if (!size)
194 		return;
195 
196 	nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
197 	efi_bs_call(free_pages, addr, nr_pages);
198 }
199 
200 /*
201  * Relocate a kernel image, either compressed or uncompressed.
202  * In the ARM64 case, all kernel images are currently
203  * uncompressed, and as such when we relocate it we need to
204  * allocate additional space for the BSS segment. Any low
205  * memory that this function should avoid needs to be
206  * unavailable in the EFI memory map, as if the preferred
207  * address is not available the lowest available address will
208  * be used.
209  */
210 efi_status_t efi_relocate_kernel(unsigned long *image_addr,
211 				 unsigned long image_size,
212 				 unsigned long alloc_size,
213 				 unsigned long preferred_addr,
214 				 unsigned long alignment,
215 				 unsigned long min_addr)
216 {
217 	unsigned long cur_image_addr;
218 	unsigned long new_addr = 0;
219 	efi_status_t status;
220 	unsigned long nr_pages;
221 	efi_physical_addr_t efi_addr = preferred_addr;
222 
223 	if (!image_addr || !image_size || !alloc_size)
224 		return EFI_INVALID_PARAMETER;
225 	if (alloc_size < image_size)
226 		return EFI_INVALID_PARAMETER;
227 
228 	cur_image_addr = *image_addr;
229 
230 	/*
231 	 * The EFI firmware loader could have placed the kernel image
232 	 * anywhere in memory, but the kernel has restrictions on the
233 	 * max physical address it can run at.  Some architectures
234 	 * also have a prefered address, so first try to relocate
235 	 * to the preferred address.  If that fails, allocate as low
236 	 * as possible while respecting the required alignment.
237 	 */
238 	nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
239 	status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
240 			     EFI_LOADER_DATA, nr_pages, &efi_addr);
241 	new_addr = efi_addr;
242 	/*
243 	 * If preferred address allocation failed allocate as low as
244 	 * possible.
245 	 */
246 	if (status != EFI_SUCCESS) {
247 		status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
248 					     min_addr);
249 	}
250 	if (status != EFI_SUCCESS) {
251 		pr_efi_err("Failed to allocate usable memory for kernel.\n");
252 		return status;
253 	}
254 
255 	/*
256 	 * We know source/dest won't overlap since both memory ranges
257 	 * have been allocated by UEFI, so we can safely use memcpy.
258 	 */
259 	memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
260 
261 	/* Return the new address of the relocated image. */
262 	*image_addr = new_addr;
263 
264 	return status;
265 }
266