1 #include <dragonstub/dragonstub.h>
2 #include <dragonstub/linux/align.h>
3 #include <dragonstub/linux/math.h>
4
5
6 /**
7 * efi_allocate_pages_aligned() - Allocate memory pages
8 * @size: minimum number of bytes to allocate
9 * @addr: On return the address of the first allocated page. The first
10 * allocated page has alignment EFI_ALLOC_ALIGN which is an
11 * architecture dependent multiple of the page size.
12 * @max: the address that the last allocated memory page shall not
13 * exceed
14 * @align: minimum alignment of the base of the allocation
15 *
16 * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
17 * to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will
18 * not exceed the address given by @max.
19 *
20 * Return: status code
21 */
efi_allocate_pages_aligned(unsigned long size,unsigned long * addr,unsigned long max,unsigned long align,int memory_type)22 efi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr,
23 unsigned long max, unsigned long align,
24 int memory_type)
25 {
26 efi_physical_addr_t alloc_addr;
27 efi_status_t status;
28 int slack;
29
30 max = min(max, EFI_ALLOC_LIMIT);
31
32 if (align < EFI_ALLOC_ALIGN)
33 align = EFI_ALLOC_ALIGN;
34
35 alloc_addr = ALIGN_DOWN(max + 1, align) - 1;
36 size = round_up(size, EFI_ALLOC_ALIGN);
37 slack = align / EFI_PAGE_SIZE - 1;
38
39 status = efi_bs_call(AllocatePages, EFI_ALLOCATE_MAX_ADDRESS,
40 memory_type, size / EFI_PAGE_SIZE + slack,
41 &alloc_addr);
42 if (status != EFI_SUCCESS)
43 return status;
44
45 *addr = ALIGN_UP((unsigned long)alloc_addr, align);
46
47 if (slack > 0) {
48 int l = (alloc_addr & (align - 1)) / EFI_PAGE_SIZE;
49
50 if (l) {
51 efi_bs_call(FreePages, alloc_addr, slack - l + 1);
52 slack = l - 1;
53 }
54 if (slack)
55 efi_bs_call(FreePages, *addr + size, slack);
56 }
57 return EFI_SUCCESS;
58 }
59