Skip to content

Commit 762cd28

Browse files
committed
efi/libstub: arm32: Use low allocation for the uncompressed kernel
Before commit d0f9ca9 ("ARM: decompressor: run decompressor in place if loaded via UEFI") we were rather limited in the choice of base address for the uncompressed kernel, as we were relying on the logic in the decompressor that blindly rounds down the decompressor execution address to the next multiple of 128 MiB, and decompresses the kernel there. For this reason, we have a lot of complicated memory region handling code, to ensure that this memory window is available, even though it could be occupied by reserved regions or other allocations that may or may not collide with the uncompressed image. Today, we simply pass the target address for the decompressed image to the decompressor directly, and so we can choose a suitable window just by finding a 16 MiB aligned region, while taking TEXT_OFFSET and the region for the swapper page tables into account. So let's get rid of the complicated logic, and instead, use the existing bottom up allocation routine to allocate a suitable window as low as possible, and carve out a memory region that has the right properties. Note that this removes any dependencies on the 'dram_base' argument to handle_kernel_image(), and so this is removed as well. Given that this was the only remaining use of dram_base, the code that produces it is removed entirely as well. Reviewed-by: Maxim Uvarov <maxim.uvarov@linaro.org> Tested-by: Maxim Uvarov <maxim.uvarov@linaro.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 1a895db commit 762cd28

4 files changed

Lines changed: 38 additions & 189 deletions

File tree

drivers/firmware/efi/libstub/arm32-stub.c

Lines changed: 37 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -113,162 +113,58 @@ void free_screen_info(struct screen_info *si)
113113
efi_bs_call(free_pool, si);
114114
}
115115

116-
static efi_status_t reserve_kernel_base(unsigned long dram_base,
117-
unsigned long *reserve_addr,
118-
unsigned long *reserve_size)
119-
{
120-
efi_physical_addr_t alloc_addr;
121-
efi_memory_desc_t *memory_map;
122-
unsigned long nr_pages, map_size, desc_size, buff_size;
123-
efi_status_t status;
124-
unsigned long l;
125-
126-
struct efi_boot_memmap map = {
127-
.map = &memory_map,
128-
.map_size = &map_size,
129-
.desc_size = &desc_size,
130-
.desc_ver = NULL,
131-
.key_ptr = NULL,
132-
.buff_size = &buff_size,
133-
};
134-
135-
/*
136-
* Reserve memory for the uncompressed kernel image. This is
137-
* all that prevents any future allocations from conflicting
138-
* with the kernel. Since we can't tell from the compressed
139-
* image how much DRAM the kernel actually uses (due to BSS
140-
* size uncertainty) we allocate the maximum possible size.
141-
* Do this very early, as prints can cause memory allocations
142-
* that may conflict with this.
143-
*/
144-
alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE;
145-
nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE;
146-
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
147-
EFI_BOOT_SERVICES_DATA, nr_pages, &alloc_addr);
148-
if (status == EFI_SUCCESS) {
149-
if (alloc_addr == dram_base) {
150-
*reserve_addr = alloc_addr;
151-
*reserve_size = MAX_UNCOMP_KERNEL_SIZE;
152-
return EFI_SUCCESS;
153-
}
154-
/*
155-
* If we end up here, the allocation succeeded but starts below
156-
* dram_base. This can only occur if the real base of DRAM is
157-
* not a multiple of 128 MB, in which case dram_base will have
158-
* been rounded up. Since this implies that a part of the region
159-
* was already occupied, we need to fall through to the code
160-
* below to ensure that the existing allocations don't conflict.
161-
* For this reason, we use EFI_BOOT_SERVICES_DATA above and not
162-
* EFI_LOADER_DATA, which we wouldn't able to distinguish from
163-
* allocations that we want to disallow.
164-
*/
165-
}
166-
167-
/*
168-
* If the allocation above failed, we may still be able to proceed:
169-
* if the only allocations in the region are of types that will be
170-
* released to the OS after ExitBootServices(), the decompressor can
171-
* safely overwrite them.
172-
*/
173-
status = efi_get_memory_map(&map);
174-
if (status != EFI_SUCCESS) {
175-
efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n");
176-
return status;
177-
}
178-
179-
for (l = 0; l < map_size; l += desc_size) {
180-
efi_memory_desc_t *desc;
181-
u64 start, end;
182-
183-
desc = (void *)memory_map + l;
184-
start = desc->phys_addr;
185-
end = start + desc->num_pages * EFI_PAGE_SIZE;
186-
187-
/* Skip if entry does not intersect with region */
188-
if (start >= dram_base + MAX_UNCOMP_KERNEL_SIZE ||
189-
end <= dram_base)
190-
continue;
191-
192-
switch (desc->type) {
193-
case EFI_BOOT_SERVICES_CODE:
194-
case EFI_BOOT_SERVICES_DATA:
195-
/* Ignore types that are released to the OS anyway */
196-
continue;
197-
198-
case EFI_CONVENTIONAL_MEMORY:
199-
/* Skip soft reserved conventional memory */
200-
if (efi_soft_reserve_enabled() &&
201-
(desc->attribute & EFI_MEMORY_SP))
202-
continue;
203-
204-
/*
205-
* Reserve the intersection between this entry and the
206-
* region.
207-
*/
208-
start = max(start, (u64)dram_base);
209-
end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE);
210-
211-
status = efi_bs_call(allocate_pages,
212-
EFI_ALLOCATE_ADDRESS,
213-
EFI_LOADER_DATA,
214-
(end - start) / EFI_PAGE_SIZE,
215-
&start);
216-
if (status != EFI_SUCCESS) {
217-
efi_err("reserve_kernel_base(): alloc failed.\n");
218-
goto out;
219-
}
220-
break;
221-
222-
case EFI_LOADER_CODE:
223-
case EFI_LOADER_DATA:
224-
/*
225-
* These regions may be released and reallocated for
226-
* another purpose (including EFI_RUNTIME_SERVICE_DATA)
227-
* at any time during the execution of the OS loader,
228-
* so we cannot consider them as safe.
229-
*/
230-
default:
231-
/*
232-
* Treat any other allocation in the region as unsafe */
233-
status = EFI_OUT_OF_RESOURCES;
234-
goto out;
235-
}
236-
}
237-
238-
status = EFI_SUCCESS;
239-
out:
240-
efi_bs_call(free_pool, memory_map);
241-
return status;
242-
}
243-
244116
efi_status_t handle_kernel_image(unsigned long *image_addr,
245117
unsigned long *image_size,
246118
unsigned long *reserve_addr,
247119
unsigned long *reserve_size,
248-
unsigned long dram_base,
249120
efi_loaded_image_t *image)
250121
{
251-
unsigned long kernel_base;
122+
const int slack = TEXT_OFFSET - 5 * PAGE_SIZE;
123+
int alloc_size = MAX_UNCOMP_KERNEL_SIZE + EFI_PHYS_ALIGN;
124+
unsigned long alloc_base, kernel_base;
252125
efi_status_t status;
253126

254-
/* use a 16 MiB aligned base for the decompressed kernel */
255-
kernel_base = round_up(dram_base, EFI_PHYS_ALIGN) + TEXT_OFFSET;
256-
257127
/*
258-
* Note that some platforms (notably, the Raspberry Pi 2) put
259-
* spin-tables and other pieces of firmware at the base of RAM,
260-
* abusing the fact that the window of TEXT_OFFSET bytes at the
261-
* base of the kernel image is only partially used at the moment.
262-
* (Up to 5 pages are used for the swapper page tables)
128+
* Allocate space for the decompressed kernel as low as possible.
129+
* The region should be 16 MiB aligned, but the first 'slack' bytes
130+
* are not used by Linux, so we allow those to be occupied by the
131+
* firmware.
263132
*/
264-
status = reserve_kernel_base(kernel_base - 5 * PAGE_SIZE, reserve_addr,
265-
reserve_size);
133+
status = efi_low_alloc_above(alloc_size, EFI_PAGE_SIZE, &alloc_base, 0x0);
266134
if (status != EFI_SUCCESS) {
267135
efi_err("Unable to allocate memory for uncompressed kernel.\n");
268136
return status;
269137
}
270138

271-
*image_addr = kernel_base;
139+
if ((alloc_base % EFI_PHYS_ALIGN) > slack) {
140+
/*
141+
* More than 'slack' bytes are already occupied at the base of
142+
* the allocation, so we need to advance to the next 16 MiB block.
143+
*/
144+
kernel_base = round_up(alloc_base, EFI_PHYS_ALIGN);
145+
efi_info("Free memory starts at 0x%lx, setting kernel_base to 0x%lx\n",
146+
alloc_base, kernel_base);
147+
} else {
148+
kernel_base = round_down(alloc_base, EFI_PHYS_ALIGN);
149+
}
150+
151+
*reserve_addr = kernel_base + slack;
152+
*reserve_size = MAX_UNCOMP_KERNEL_SIZE;
153+
154+
/* now free the parts that we will not use */
155+
if (*reserve_addr > alloc_base) {
156+
efi_bs_call(free_pages, alloc_base,
157+
(*reserve_addr - alloc_base) / EFI_PAGE_SIZE);
158+
alloc_size -= *reserve_addr - alloc_base;
159+
}
160+
efi_bs_call(free_pages, *reserve_addr + MAX_UNCOMP_KERNEL_SIZE,
161+
(alloc_size - MAX_UNCOMP_KERNEL_SIZE) / EFI_PAGE_SIZE);
162+
163+
*image_addr = kernel_base + TEXT_OFFSET;
272164
*image_size = 0;
165+
166+
efi_debug("image addr == 0x%lx, reserve_addr == 0x%lx\n",
167+
*image_addr, *reserve_addr);
168+
273169
return EFI_SUCCESS;
274170
}

drivers/firmware/efi/libstub/arm64-stub.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
5050
unsigned long *image_size,
5151
unsigned long *reserve_addr,
5252
unsigned long *reserve_size,
53-
unsigned long dram_base,
5453
efi_loaded_image_t *image)
5554
{
5655
efi_status_t status;

drivers/firmware/efi/libstub/efi-stub.c

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -87,40 +87,6 @@ static void install_memreserve_table(void)
8787
efi_err("Failed to install memreserve config table!\n");
8888
}
8989

90-
static unsigned long get_dram_base(void)
91-
{
92-
efi_status_t status;
93-
unsigned long map_size, buff_size;
94-
unsigned long membase = EFI_ERROR;
95-
struct efi_memory_map map;
96-
efi_memory_desc_t *md;
97-
struct efi_boot_memmap boot_map;
98-
99-
boot_map.map = (efi_memory_desc_t **)&map.map;
100-
boot_map.map_size = &map_size;
101-
boot_map.desc_size = &map.desc_size;
102-
boot_map.desc_ver = NULL;
103-
boot_map.key_ptr = NULL;
104-
boot_map.buff_size = &buff_size;
105-
106-
status = efi_get_memory_map(&boot_map);
107-
if (status != EFI_SUCCESS)
108-
return membase;
109-
110-
map.map_end = map.map + map_size;
111-
112-
for_each_efi_memory_desc_in_map(&map, md) {
113-
if (md->attribute & EFI_MEMORY_WB) {
114-
if (membase > md->phys_addr)
115-
membase = md->phys_addr;
116-
}
117-
}
118-
119-
efi_bs_call(free_pool, map.map);
120-
121-
return membase;
122-
}
123-
12490
/*
12591
* EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
12692
* that is described in the PE/COFF header. Most of the code is the same
@@ -134,7 +100,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
134100
efi_status_t status;
135101
unsigned long image_addr;
136102
unsigned long image_size = 0;
137-
unsigned long dram_base;
138103
/* addr/point and size pairs for memory management*/
139104
unsigned long initrd_addr = 0;
140105
unsigned long initrd_size = 0;
@@ -174,13 +139,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
174139
goto fail;
175140
}
176141

177-
dram_base = get_dram_base();
178-
if (dram_base == EFI_ERROR) {
179-
efi_err("Failed to find DRAM base\n");
180-
status = EFI_LOAD_ERROR;
181-
goto fail;
182-
}
183-
184142
/*
185143
* Get the command line from EFI, using the LOADED_IMAGE
186144
* protocol. We are going to copy the command line into the
@@ -218,7 +176,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
218176
status = handle_kernel_image(&image_addr, &image_size,
219177
&reserve_addr,
220178
&reserve_size,
221-
dram_base, image);
179+
image);
222180
if (status != EFI_SUCCESS) {
223181
efi_err("Failed to relocate kernel\n");
224182
goto fail_free_screeninfo;

drivers/firmware/efi/libstub/efistub.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
#include <linux/types.h>
1111
#include <asm/efi.h>
1212

13-
/* error code which can't be mistaken for valid address */
14-
#define EFI_ERROR (~0UL)
15-
1613
/*
1714
* __init annotations should not be used in the EFI stub, since the code is
1815
* either included in the decompressor (x86, ARM) where they have no effect,
@@ -789,7 +786,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
789786
unsigned long *image_size,
790787
unsigned long *reserve_addr,
791788
unsigned long *reserve_size,
792-
unsigned long dram_base,
793789
efi_loaded_image_t *image);
794790

795791
asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,

0 commit comments

Comments
 (0)