diff options
author | Tom Rini <trini@konsulko.com> | 2016-10-19 07:48:16 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2016-10-19 07:48:16 -0400 |
commit | 3431b392ad50ff37fa3d6e7715c6a99c74d692dc (patch) | |
tree | 53b6785acaa658a60c6a854af4dea9040f826b48 /lib/efi_loader/efi_memory.c | |
parent | 68ff827ec74fdca8f17d469f22e1032ed14cb795 (diff) | |
parent | 3fb97e267a5e136d8386a7cb1d5b4fe63af518eb (diff) |
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
Patch queue for efi - 2016-10-19
Highlights this time around:
- Add run time service (power control) support for PSCI (fixed in v3)
- Add efi gop pointer exposure
- SMBIOS support for EFI (on ARM)
- efi pool memory unmap support (needed for 4.8)
- initial x86 efi payload support (fixed up in v2)
- various bug fixes
Signed-off-by: Tom Rini <trini@konsulko.com>
Conflicts:
include/tables_csum.h
Diffstat (limited to 'lib/efi_loader/efi_memory.c')
-rw-r--r-- | lib/efi_loader/efi_memory.c | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 80e4e26e05e..95aa590c8af 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 @@ -62,9 +75,17 @@ static void efi_mem_sort(void) * Unmaps all memory occupied by the carve_desc region from the * list entry pointed to by map. * - * Returns 1 if carving was performed or 0 if the regions don't overlap. - * Returns -1 if it would affect non-RAM regions but overlap_only_ram is set. - * Carving is only guaranteed to complete when all regions return 0. + * Returns EFI_CARVE_NO_OVERLAP if the regions don't overlap. + * Returns EFI_CARVE_OVERLAPS_NONRAM if the carve and map overlap, + * and the map contains anything but free ram. + * (only when overlap_only_ram is true) + * Returns EFI_CARVE_LOOP_AGAIN if the mapping list should be traversed + * again, as it has been altered + * Returns the number of overlapping pages. The pages are removed from + * the mapping list. + * + * In case of EFI_CARVE_OVERLAPS_NONRAM it is the callers responsibility + * to readd the already carved out pages to the mapping. */ static int efi_mem_carve_out(struct efi_mem_list *map, struct efi_mem_desc *carve_desc, @@ -95,10 +116,13 @@ static int efi_mem_carve_out(struct efi_mem_list *map, if (map_end == carve_end) { /* Full overlap, just remove map */ list_del(&map->link); + free(map); + } else { + map->desc.physical_start = carve_end; + map->desc.num_pages = (map_end - carve_end) + >> EFI_PAGE_SHIFT; } - map_desc->physical_start = carve_end; - map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; return (carve_end - carve_start) >> EFI_PAGE_SHIFT; } @@ -114,7 +138,8 @@ static int efi_mem_carve_out(struct efi_mem_list *map, newmap->desc = map->desc; newmap->desc.physical_start = carve_start; newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT; - list_add_tail(&newmap->link, &efi_mem); + /* Insert before current entry (descending address order) */ + list_add_tail(&newmap->link, &map->link); /* Shrink the map to [ map_start ... carve_start ] */ map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; @@ -315,8 +340,52 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) { - /* We don't free, let's cross our fingers we have plenty RAM */ - return EFI_SUCCESS; + uint64_t r = 0; + + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + /* Merging of adjacent free regions is missing */ + + if (r == memory) + return EFI_SUCCESS; + + return EFI_NOT_FOUND; +} + +efi_status_t efi_allocate_pool(int pool_type, unsigned long size, + void **buffer) +{ + efi_status_t r; + efi_physical_addr_t t; + 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) { + 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; } efi_status_t efi_get_memory_map(unsigned long *memory_map_size, @@ -328,6 +397,7 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, ulong map_size = 0; int map_entries = 0; struct list_head *lhandle; + unsigned long provided_map_size = *memory_map_size; list_for_each(lhandle, &efi_mem) map_entries++; @@ -342,7 +412,7 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size, if (descriptor_version) *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; - if (*memory_map_size < map_size) + if (provided_map_size < map_size) return EFI_BUFFER_TOO_SMALL; /* Copy list into array */ |