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