common: Drop net.h from common header
[oweals/u-boot.git] / lib / efi_loader / efi_memory.c
index dbe29b89603e4898abef1a72b842964f3e56c3f2..44b8a2e09f0a543ae112a131a797a4b14347ec74 100644 (file)
@@ -7,9 +7,11 @@
 
 #include <common.h>
 #include <efi_loader.h>
+#include <init.h>
 #include <malloc.h>
 #include <mapmem.h>
 #include <watchdog.h>
+#include <asm/cache.h>
 #include <linux/list_sort.h>
 #include <linux/sizes.h>
 
@@ -37,17 +39,21 @@ void *efi_bounce_buffer;
 #endif
 
 /**
- * efi_pool_allocation - memory block allocated from pool
+ * struct efi_pool_allocation - memory block allocated from pool
  *
  * @num_pages: number of pages allocated
  * @checksum:  checksum
+ * @data:      allocated pool memory
  *
- * U-Boot services each EFI AllocatePool request as a separate
- * (multiple) page allocation.  We have to track the number of pages
+ * U-Boot services each UEFI 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.
+ *
+ * The checksum calculated in function checksum() is used in FreePool() to avoid
+ * freeing memory not allocated by AllocatePool() and duplicate freeing.
+ *
  * 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.
+ * prepend each allocation with these header fields.
  */
 struct efi_pool_allocation {
        u64 num_pages;
@@ -193,6 +199,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
                        free(map);
                } else {
                        map->desc.physical_start = carve_end;
+                       map->desc.virtual_start = carve_end;
                        map->desc.num_pages = (map_end - carve_end)
                                              >> EFI_PAGE_SHIFT;
                }
@@ -211,6 +218,7 @@ static s64 efi_mem_carve_out(struct efi_mem_list *map,
        newmap = calloc(1, sizeof(*newmap));
        newmap->desc = map->desc;
        newmap->desc.physical_start = carve_start;
+       newmap->desc.virtual_start = carve_start;
        newmap->desc.num_pages = (map_end - carve_start) >> EFI_PAGE_SHIFT;
        /* Insert before current entry (descending address order) */
        list_add_tail(&newmap->link, &map->link);
@@ -221,13 +229,24 @@ 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_pg() - add pages 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
+ */
+static efi_status_t efi_add_memory_map_pg(u64 start, u64 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");
@@ -236,7 +255,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));
@@ -274,7 +293,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;
@@ -304,7 +323,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 */
@@ -313,7 +332,74 @@ 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;
+}
+
+/**
+ * efi_add_memory_map() - add memory area to the memory map
+ *
+ * @start:             start address of the memory area
+ * @size:              length in bytes of the memory area
+ * @memory_type:       type of memory added
+ *
+ * Return:             status code
+ *
+ * This function automatically aligns the start and size of the memory area
+ * to EFI_PAGE_SIZE.
+ */
+efi_status_t efi_add_memory_map(u64 start, u64 size, int memory_type)
+{
+       u64 pages;
+
+       pages = efi_size_in_pages(size + (start & EFI_PAGE_MASK));
+       start &= ~EFI_PAGE_MASK;
+
+       return efi_add_memory_map_pg(start, pages, memory_type, false);
+}
+
+/**
+ * efi_check_allocated() - validate address to be freed
+ *
+ * Check that the address is within allocated memory:
+ *
+ * * 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
+ * @must_be_allocated: return success if the page is allocated
+ * Return:             status code
+ */
+static efi_status_t efi_check_allocated(u64 addr, bool must_be_allocated)
+{
+       struct efi_mem_list *item;
+
+       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 (must_be_allocated ^
+                           (item->desc.type == EFI_CONVENTIONAL_MEMORY))
+                               return EFI_SUCCESS;
+                       else
+                               return EFI_NOT_FOUND;
+               }
+       }
+
+       return EFI_NOT_FOUND;
 }
 
 static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr)
@@ -371,9 +457,13 @@ 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 */
+       if (memory_type >= EFI_PERSISTENT_MEMORY_TYPE &&
+           memory_type <= 0x6FFFFFFF)
+               return EFI_INVALID_PARAMETER;
        if (!memory)
                return EFI_INVALID_PARAMETER;
 
@@ -381,43 +471,36 @@ 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_NOT_FOUND;
-                       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_NOT_FOUND;
-                       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 */
+       ret = efi_add_memory_map_pg(addr, pages, memory_type, true);
+       if (ret != 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)
@@ -443,22 +526,27 @@ 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, true);
+       if (ret != EFI_SUCCESS)
+               return ret;
 
        /* Sanity check */
-       if (!memory || (memory & EFI_PAGE_MASK)) {
+       if (!memory || (memory & EFI_PAGE_MASK) || !pages) {
                printf("%s: illegal free 0x%llx, 0x%zx\n", __func__,
                       memory, pages);
                return EFI_INVALID_PARAMETER;
        }
 
-       r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false);
+       ret = efi_add_memory_map_pg(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;
 }
 
 /**
@@ -505,12 +593,16 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer)
  */
 efi_status_t efi_free_pool(void *buffer)
 {
-       efi_status_t r;
+       efi_status_t ret;
        struct efi_pool_allocation *alloc;
 
-       if (buffer == NULL)
+       if (!buffer)
                return EFI_INVALID_PARAMETER;
 
+       ret = efi_check_allocated((uintptr_t)buffer, true);
+       if (ret != EFI_SUCCESS)
+               return ret;
+
        alloc = container_of(buffer, struct efi_pool_allocation, data);
 
        /* Check that this memory was allocated by efi_allocate_pool() */
@@ -522,9 +614,9 @@ efi_status_t efi_free_pool(void *buffer)
        /* Avoid double free */
        alloc->checksum = 0;
 
-       r = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
+       ret = efi_free_pages((uintptr_t)alloc, alloc->num_pages);
 
-       return r;
+       return ret;
 }
 
 /*
@@ -561,18 +653,18 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
 
        *memory_map_size = map_size;
 
-       if (provided_map_size < map_size)
-               return EFI_BUFFER_TOO_SMALL;
-
-       if (!memory_map)
-               return EFI_INVALID_PARAMETER;
-
        if (descriptor_size)
                *descriptor_size = sizeof(struct efi_mem_desc);
 
        if (descriptor_version)
                *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
 
+       if (provided_map_size < map_size)
+               return EFI_BUFFER_TOO_SMALL;
+
+       if (!memory_map)
+               return EFI_INVALID_PARAMETER;
+
        /* Copy list into array */
        /* Return the list in ascending order */
        memory_map = &memory_map[map_entries - 1];
@@ -590,6 +682,54 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size,
        return EFI_SUCCESS;
 }
 
+/**
+ * efi_add_conventional_memory_map() - add a RAM memory area to the map
+ *
+ * @ram_start:         start address of a RAM memory area
+ * @ram_end:           end address of a RAM memory area
+ * @ram_top:           max address to be used as conventional memory
+ * Return:             status code
+ */
+efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
+                                            u64 ram_top)
+{
+       u64 pages;
+
+       /* Remove partial pages */
+       ram_end &= ~EFI_PAGE_MASK;
+       ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+
+       if (ram_end <= ram_start) {
+               /* Invalid mapping */
+               return EFI_INVALID_PARAMETER;
+       }
+
+       pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
+
+       efi_add_memory_map_pg(ram_start, pages,
+                             EFI_CONVENTIONAL_MEMORY, false);
+
+       /*
+        * Boards may indicate to the U-Boot memory core that they
+        * can not support memory above ram_top. Let's honor this
+        * in the efi_loader subsystem too by declaring any memory
+        * above ram_top as "already occupied by firmware".
+        */
+       if (ram_top < ram_start) {
+               /* ram_top is before this region, reserve all */
+               efi_add_memory_map_pg(ram_start, pages,
+                                     EFI_BOOT_SERVICES_DATA, true);
+       } else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
+               /* ram_top is inside this region, reserve parts */
+               pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
+
+               efi_add_memory_map_pg(ram_top, pages,
+                                     EFI_BOOT_SERVICES_DATA, true);
+       }
+
+       return EFI_SUCCESS;
+}
+
 __weak void efi_add_known_memory(void)
 {
        u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
@@ -607,42 +747,12 @@ __weak void efi_add_known_memory(void)
 
        /* Add RAM */
        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
-               u64 ram_end, ram_start, pages;
+               u64 ram_end, ram_start;
 
                ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
                ram_end = ram_start + gd->bd->bi_dram[i].size;
 
-               /* Remove partial pages */
-               ram_end &= ~EFI_PAGE_MASK;
-               ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
-
-               if (ram_end <= ram_start) {
-                       /* Invalid mapping, keep going. */
-                       continue;
-               }
-
-               pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
-
-               efi_add_memory_map(ram_start, pages,
-                                  EFI_CONVENTIONAL_MEMORY, false);
-
-               /*
-                * Boards may indicate to the U-Boot memory core that they
-                * can not support memory above ram_top. Let's honor this
-                * in the efi_loader subsystem too by declaring any memory
-                * above ram_top as "already occupied by firmware".
-                */
-               if (ram_top < ram_start) {
-                       /* ram_top is before this region, reserve all */
-                       efi_add_memory_map(ram_start, pages,
-                                          EFI_BOOT_SERVICES_DATA, true);
-               } else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
-                       /* ram_top is inside this region, reserve parts */
-                       pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
-
-                       efi_add_memory_map(ram_top, pages,
-                                          EFI_BOOT_SERVICES_DATA, true);
-               }
+               efi_add_conventional_memory_map(ram_start, ram_end, ram_top);
        }
 }
 
@@ -655,9 +765,12 @@ static void add_u_boot_and_runtime(void)
        unsigned long uboot_stack_size = 16 * 1024 * 1024;
 
        /* Add U-Boot */
-       uboot_start = (gd->start_addr_sp - uboot_stack_size) & ~EFI_PAGE_MASK;
-       uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT;
-       efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false);
+       uboot_start = ((uintptr_t)map_sysmem(gd->start_addr_sp, 0) -
+                      uboot_stack_size) & ~EFI_PAGE_MASK;
+       uboot_pages = ((uintptr_t)map_sysmem(gd->ram_top - 1, 0) -
+                      uboot_start + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT;
+       efi_add_memory_map_pg(uboot_start, uboot_pages, EFI_LOADER_DATA,
+                             false);
 
 #if defined(__aarch64__)
        /*
@@ -676,16 +789,15 @@ static void add_u_boot_and_runtime(void)
        runtime_end = (ulong)&__efi_runtime_stop;
        runtime_end = (runtime_end + runtime_mask) & ~runtime_mask;
        runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT;
-       efi_add_memory_map(runtime_start, runtime_pages,
-                          EFI_RUNTIME_SERVICES_CODE, false);
+       efi_add_memory_map_pg(runtime_start, runtime_pages,
+                             EFI_RUNTIME_SERVICES_CODE, false);
 }
 
 int efi_memory_init(void)
 {
        efi_add_known_memory();
 
-       if (!IS_ENABLED(CONFIG_SANDBOX))
-               add_u_boot_and_runtime();
+       add_u_boot_and_runtime();
 
 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
        /* Request a 32bit 64MB bounce buffer region */