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