efi_loader: Change return type of efi_add_memory_map()
[oweals/u-boot.git] / lib / efi_loader / efi_memory.c
index adbeb1db6b75d17aaf3b8b8a67310cb550de017a..4c0216b1d245a1a8914d34a6f3c83a7093adab05 100644 (file)
@@ -223,13 +223,23 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
        return EFI_CARVE_LOOP_AGAIN;
 }
 
-uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
-                           bool overlap_only_ram)
+/**
+ * efi_add_memory_map() - add memory area to the memory map
+ *
+ * @start:             start address, must be a multiple of EFI_PAGE_SIZE
+ * @pages:             number of pages to add
+ * @memory_type:       type of memory added
+ * @overlap_only_ram:  the memory area must overlap existing
+ * Return:             status code
+ */
+efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
+                               bool overlap_only_ram)
 {
        struct list_head *lhandle;
        struct efi_mem_list *newlist;
        bool carve_again;
        uint64_t carved_pages = 0;
+       struct efi_event *evt;
 
        EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__,
                  start, pages, memory_type, overlap_only_ram ? "yes" : "no");
@@ -238,7 +248,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
                return EFI_INVALID_PARAMETER;
 
        if (!pages)
-               return start;
+               return EFI_SUCCESS;
 
        ++efi_memory_map_key;
        newlist = calloc(1, sizeof(*newlist));
@@ -276,7 +286,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
                                 * The user requested to only have RAM overlaps,
                                 * but we hit a non-RAM region. Error out.
                                 */
-                               return 0;
+                               return EFI_NO_MAPPING;
                        case EFI_CARVE_NO_OVERLAP:
                                /* Just ignore this list entry */
                                break;
@@ -306,7 +316,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
                 * The payload wanted to have RAM overlaps, but we overlapped
                 * with an unallocated region. Error out.
                 */
-               return 0;
+               return EFI_NO_MAPPING;
        }
 
        /* Add our new map */
@@ -315,7 +325,17 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
        /* And make sure memory is listed in descending order */
        efi_mem_sort();
 
-       return start;
+       /* Notify that the memory map was changed */
+       list_for_each_entry(evt, &efi_events, link) {
+               if (evt->group &&
+                   !guidcmp(evt->group,
+                            &efi_guid_event_group_memory_map_change)) {
+                       efi_signal_event(evt);
+                       break;
+               }
+       }
+
+       return EFI_SUCCESS;
 }
 
 /**
@@ -323,28 +343,27 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
  *
  * Check that the address is within allocated memory:
  *
- * * The address cannot be NULL.
  * * The address must be in a range of the memory map.
  * * The address may not point to EFI_CONVENTIONAL_MEMORY.
  *
  * Page alignment is not checked as this is not a requirement of
  * efi_free_pool().
  *
- * @addr:      address of page to be freed
- * Return:     status code
+ * @addr:              address of page to be freed
+ * @must_be_allocated: return success if the page is allocated
+ * Return:             status code
  */
-static efi_status_t efi_check_allocated(u64 addr)
+static efi_status_t efi_check_allocated(u64 addr, bool must_be_allocated)
 {
        struct efi_mem_list *item;
 
-       if (!addr)
-               return EFI_INVALID_PARAMETER;
        list_for_each_entry(item, &efi_mem, link) {
                u64 start = item->desc.physical_start;
                u64 end = start + (item->desc.num_pages << EFI_PAGE_SHIFT);
 
                if (addr >= start && addr < end) {
-                       if (item->desc.type != EFI_CONVENTIONAL_MEMORY)
+                       if (must_be_allocated ^
+                           (item->desc.type == EFI_CONVENTIONAL_MEMORY))
                                return EFI_SUCCESS;
                        else
                                return EFI_NOT_FOUND;
@@ -409,7 +428,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
                                efi_uintn_t pages, uint64_t *memory)
 {
        u64 len = pages << EFI_PAGE_SHIFT;
-       efi_status_t r = EFI_SUCCESS;
+       efi_status_t ret;
        uint64_t addr;
 
        /* Check import parameters */
@@ -423,43 +442,35 @@ efi_status_t efi_allocate_pages(int type, int memory_type,
        case EFI_ALLOCATE_ANY_PAGES:
                /* Any page */
                addr = efi_find_free_memory(len, -1ULL);
-               if (!addr) {
-                       r = EFI_OUT_OF_RESOURCES;
-                       break;
-               }
+               if (!addr)
+                       return EFI_OUT_OF_RESOURCES;
                break;
        case EFI_ALLOCATE_MAX_ADDRESS:
                /* Max address */
                addr = efi_find_free_memory(len, *memory);
-               if (!addr) {
-                       r = EFI_OUT_OF_RESOURCES;
-                       break;
-               }
+               if (!addr)
+                       return EFI_OUT_OF_RESOURCES;
                break;
        case EFI_ALLOCATE_ADDRESS:
                /* Exact address, reserve it. The addr is already in *memory. */
+               ret = efi_check_allocated(*memory, false);
+               if (ret != EFI_SUCCESS)
+                       return EFI_NOT_FOUND;
                addr = *memory;
                break;
        default:
                /* UEFI doesn't specify other allocation types */
-               r = EFI_INVALID_PARAMETER;
-               break;
+               return EFI_INVALID_PARAMETER;
        }
 
-       if (r == EFI_SUCCESS) {
-               uint64_t ret;
+       /* Reserve that map in our memory maps */
+       if (efi_add_memory_map(addr, pages, memory_type, true) != EFI_SUCCESS)
+               /* Map would overlap, bail out */
+               return  EFI_OUT_OF_RESOURCES;
 
-               /* Reserve that map in our memory maps */
-               ret = efi_add_memory_map(addr, pages, memory_type, true);
-               if (ret == addr) {
-                       *memory = addr;
-               } else {
-                       /* Map would overlap, bail out */
-                       r = EFI_OUT_OF_RESOURCES;
-               }
-       }
+       *memory = addr;
 
-       return r;
+       return EFI_SUCCESS;
 }
 
 void *efi_alloc(uint64_t len, int memory_type)
@@ -485,10 +496,9 @@ void *efi_alloc(uint64_t len, int memory_type)
  */
 efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
 {
-       uint64_t r = 0;
        efi_status_t ret;
 
-       ret = efi_check_allocated(memory);
+       ret = efi_check_allocated(memory, true);
        if (ret != EFI_SUCCESS)
                return ret;
 
@@ -499,13 +509,13 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages)
                return EFI_INVALID_PARAMETER;
        }
 
-       r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
+       ret = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
        /* Merging of adjacent free regions is missing */
 
-       if (r == memory)
-               return EFI_SUCCESS;
+       if (ret != EFI_SUCCESS)
+               return EFI_NOT_FOUND;
 
-       return EFI_NOT_FOUND;
+       return ret;
 }
 
 /**
@@ -555,7 +565,10 @@ efi_status_t efi_free_pool(void *buffer)
        efi_status_t ret;
        struct efi_pool_allocation *alloc;
 
-       ret = efi_check_allocated((uintptr_t)buffer);
+       if (!buffer)
+               return EFI_INVALID_PARAMETER;
+
+       ret = efi_check_allocated((uintptr_t)buffer, true);
        if (ret != EFI_SUCCESS)
                return ret;