Merge tag 'backlight-next-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee...
[linux-2.6-microblaze.git] / drivers / firmware / efi / libstub / relocate.c
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  */
23 static efi_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            = &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);
94 fail:
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  */
119 efi_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 }