diff options
-rw-r--r-- | include/efi_loader.h | 2 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 6 | ||||
-rw-r--r-- | lib/efi_loader/efi_memory.c | 42 |
3 files changed, 44 insertions, 6 deletions
diff --git a/include/efi_loader.h b/include/efi_loader.h index f0473aba7c..3dad24e84f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -122,6 +122,8 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages); /* EFI memory allocator for small allocations */ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, void **buffer); +/* EFI pool memory free function. */ +efi_status_t efi_free_pool(void *buffer); /* Returns the EFI memory map */ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, struct efi_mem_desc *memory_map, diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 05b93e87bf..6c8d93b261 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -141,12 +141,12 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, return EFI_EXIT(r); } -static efi_status_t EFIAPI efi_free_pool(void *buffer) +static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) { efi_status_t r; EFI_ENTRY("%p", buffer); - r = efi_free_pages((ulong)buffer, 0); + r = efi_free_pool(buffer); return EFI_EXIT(r); } @@ -736,7 +736,7 @@ static const struct efi_boot_services efi_boot_services = { .free_pages = efi_free_pages_ext, .get_memory_map = efi_get_memory_map_ext, .allocate_pool = efi_allocate_pool_ext, - .free_pool = efi_free_pool, + .free_pool = efi_free_pool_ext, .create_event = efi_create_event, .set_timer = efi_set_timer, .wait_for_event = efi_wait_for_event, diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index be642f12a9..de28db6e44 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -34,6 +34,19 @@ void *efi_bounce_buffer; #endif /* + * U-Boot services each EFI AllocatePool request as a separate + * (multiple) page allocation. We have to track the number of pages + * to be able to free the correct amount later. + * EFI requires 8 byte alignment for pool allocations, so we can + * prepend each allocation with an 64 bit header tracking the + * allocation size, and hand out the remainder to the caller. + */ +struct efi_pool_allocation { + u64 num_pages; + char data[]; +}; + +/* * Sorts the memory list from highest address to lowest address * * When allocating memory we should always start from the highest @@ -332,11 +345,34 @@ efi_status_t efi_allocate_pool(int pool_type, unsigned long size, { efi_status_t r; efi_physical_addr_t t; - u64 num_pages = (size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 num_pages = (size + sizeof(u64) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + + if (size == 0) { + *buffer = NULL; + return EFI_SUCCESS; + } r = efi_allocate_pages(0, pool_type, num_pages, &t); - if (r == EFI_SUCCESS) - *buffer = (void *)(uintptr_t)t; + + if (r == EFI_SUCCESS) { + struct efi_pool_allocation *alloc = (void *)(uintptr_t)t; + alloc->num_pages = num_pages; + *buffer = alloc->data; + } + + return r; +} + +efi_status_t efi_free_pool(void *buffer) +{ + efi_status_t r; + struct efi_pool_allocation *alloc; + + alloc = container_of(buffer, struct efi_pool_allocation, data); + /* Sanity check, was the supplied address returned by allocate_pool */ + assert(((uintptr_t)alloc & EFI_PAGE_MASK) == 0); + + r = efi_free_pages((uintptr_t)alloc, alloc->num_pages); return r; } |