Skip to content

Commit 43b1df0

Browse files
committed
efi/libstub: Add API function to allocate aligned memory
Break out the code to create an aligned page allocation from mem.c and move it into a function efi_allocate_pages_aligned() in alignedmem.c. Update efi_allocate_pages() to invoke it unless the minimum alignment equals the EFI page size (4 KB), in which case the ordinary page allocator is sufficient. This way, efi_allocate_pages_aligned() will only be pulled into the build if it is actually being used (which will be on arm64 only in the immediate future) Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 5d12da9 commit 43b1df0

File tree

4 files changed

+71
-17
lines changed

4 files changed

+71
-17
lines changed

drivers/firmware/efi/libstub/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ KCOV_INSTRUMENT := n
4242

4343
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \
4444
file.o mem.o random.o randomalloc.o pci.o \
45-
skip_spaces.o lib-cmdline.o lib-ctype.o
45+
skip_spaces.o lib-cmdline.o lib-ctype.o \
46+
alignedmem.o
4647

4748
# include the stub's generic dependencies from lib/ when building for ARM/arm64
4849
efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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_allocate_pages_aligned() - Allocate memory pages
10+
* @size: minimum number of bytes to allocate
11+
* @addr: On return the address of the first allocated page. The first
12+
* allocated page has alignment EFI_ALLOC_ALIGN which is an
13+
* architecture dependent multiple of the page size.
14+
* @max: the address that the last allocated memory page shall not
15+
* exceed
16+
* @align: minimum alignment of the base of the allocation
17+
*
18+
* Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
19+
* to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will
20+
* not exceed the address given by @max.
21+
*
22+
* Return: status code
23+
*/
24+
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
25+
unsigned long max, unsigned long align)
26+
{
27+
efi_physical_addr_t alloc_addr;
28+
efi_status_t status;
29+
int slack;
30+
31+
if (align < EFI_ALLOC_ALIGN)
32+
align = EFI_ALLOC_ALIGN;
33+
34+
alloc_addr = ALIGN_DOWN(max + 1, align) - 1;
35+
size = round_up(size, EFI_ALLOC_ALIGN);
36+
slack = align / EFI_PAGE_SIZE - 1;
37+
38+
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
39+
EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
40+
&alloc_addr);
41+
if (status != EFI_SUCCESS)
42+
return status;
43+
44+
*addr = ALIGN((unsigned long)alloc_addr, align);
45+
46+
if (slack > 0) {
47+
int l = (alloc_addr % align) / EFI_PAGE_SIZE;
48+
49+
if (l) {
50+
efi_bs_call(free_pages, alloc_addr, slack - l + 1);
51+
slack = l - 1;
52+
}
53+
if (slack)
54+
efi_bs_call(free_pages, *addr + size, slack);
55+
}
56+
return EFI_SUCCESS;
57+
}

drivers/firmware/efi/libstub/efistub.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,9 @@ efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
657657
efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
658658
unsigned long max);
659659

660+
efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
661+
unsigned long max, unsigned long align);
662+
660663
efi_status_t efi_relocate_kernel(unsigned long *image_addr,
661664
unsigned long image_size,
662665
unsigned long alloc_size,

drivers/firmware/efi/libstub/mem.c

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -93,31 +93,24 @@ efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
9393
efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
9494
unsigned long max)
9595
{
96-
efi_physical_addr_t alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
97-
int slack = EFI_ALLOC_ALIGN / EFI_PAGE_SIZE - 1;
96+
efi_physical_addr_t alloc_addr;
9897
efi_status_t status;
9998

100-
size = round_up(size, EFI_ALLOC_ALIGN);
99+
if (EFI_ALLOC_ALIGN > EFI_PAGE_SIZE)
100+
return efi_allocate_pages_aligned(size, addr, max,
101+
EFI_ALLOC_ALIGN);
102+
103+
alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
101104
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
102-
EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
105+
EFI_LOADER_DATA, DIV_ROUND_UP(size, EFI_PAGE_SIZE),
103106
&alloc_addr);
104107
if (status != EFI_SUCCESS)
105108
return status;
106109

107-
*addr = ALIGN((unsigned long)alloc_addr, EFI_ALLOC_ALIGN);
108-
109-
if (slack > 0) {
110-
int l = (alloc_addr % EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
111-
112-
if (l) {
113-
efi_bs_call(free_pages, alloc_addr, slack - l + 1);
114-
slack = l - 1;
115-
}
116-
if (slack)
117-
efi_bs_call(free_pages, *addr + size, slack);
118-
}
110+
*addr = alloc_addr;
119111
return EFI_SUCCESS;
120112
}
113+
121114
/**
122115
* efi_low_alloc_above() - allocate pages at or above given address
123116
* @size: size of the memory area to allocate

0 commit comments

Comments
 (0)