18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/efi.h> 48c2ecf20Sopenharmony_ci#include <asm/efi.h> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "efistub.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/** 98c2ecf20Sopenharmony_ci * efi_allocate_pages_aligned() - Allocate memory pages 108c2ecf20Sopenharmony_ci * @size: minimum number of bytes to allocate 118c2ecf20Sopenharmony_ci * @addr: On return the address of the first allocated page. The first 128c2ecf20Sopenharmony_ci * allocated page has alignment EFI_ALLOC_ALIGN which is an 138c2ecf20Sopenharmony_ci * architecture dependent multiple of the page size. 148c2ecf20Sopenharmony_ci * @max: the address that the last allocated memory page shall not 158c2ecf20Sopenharmony_ci * exceed 168c2ecf20Sopenharmony_ci * @align: minimum alignment of the base of the allocation 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according 198c2ecf20Sopenharmony_ci * to @align, which should be >= EFI_ALLOC_ALIGN. The last allocated page will 208c2ecf20Sopenharmony_ci * not exceed the address given by @max. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Return: status code 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ciefi_status_t efi_allocate_pages_aligned(unsigned long size, unsigned long *addr, 258c2ecf20Sopenharmony_ci unsigned long max, unsigned long align) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci efi_physical_addr_t alloc_addr; 288c2ecf20Sopenharmony_ci efi_status_t status; 298c2ecf20Sopenharmony_ci int slack; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (align < EFI_ALLOC_ALIGN) 328c2ecf20Sopenharmony_ci align = EFI_ALLOC_ALIGN; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci alloc_addr = ALIGN_DOWN(max + 1, align) - 1; 358c2ecf20Sopenharmony_ci size = round_up(size, EFI_ALLOC_ALIGN); 368c2ecf20Sopenharmony_ci slack = align / EFI_PAGE_SIZE - 1; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS, 398c2ecf20Sopenharmony_ci EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack, 408c2ecf20Sopenharmony_ci &alloc_addr); 418c2ecf20Sopenharmony_ci if (status != EFI_SUCCESS) 428c2ecf20Sopenharmony_ci return status; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci *addr = ALIGN((unsigned long)alloc_addr, align); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (slack > 0) { 478c2ecf20Sopenharmony_ci int l = (alloc_addr & (align - 1)) / EFI_PAGE_SIZE; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (l) { 508c2ecf20Sopenharmony_ci efi_bs_call(free_pages, alloc_addr, slack - l + 1); 518c2ecf20Sopenharmony_ci slack = l - 1; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci if (slack) 548c2ecf20Sopenharmony_ci efi_bs_call(free_pages, *addr + size, slack); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci return EFI_SUCCESS; 578c2ecf20Sopenharmony_ci} 58