]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - lib/efi_loader/efi_memory.c
ARM: tegra: set MMC pin mux in board_init()
[karo-tx-uboot.git] / lib / efi_loader / efi_memory.c
index 9e669f510266a653e5c81f3b9df9e85486e37040..80e4e26e05ea266f182d545eb6491a4d9f7810d5 100644 (file)
@@ -6,8 +6,6 @@
  *  SPDX-License-Identifier:     GPL-2.0+
  */
 
-/* #define DEBUG_EFI */
-
 #include <common.h>
 #include <efi_loader.h>
 #include <malloc.h>
@@ -24,6 +22,10 @@ struct efi_mem_list {
        struct efi_mem_desc desc;
 };
 
+#define EFI_CARVE_NO_OVERLAP           -1
+#define EFI_CARVE_LOOP_AGAIN           -2
+#define EFI_CARVE_OVERLAPS_NONRAM      -3
+
 /* This list contains all memory map items */
 LIST_HEAD(efi_mem);
 
@@ -78,11 +80,11 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
 
        /* check whether we're overlapping */
        if ((carve_end <= map_start) || (carve_start >= map_end))
-               return 0;
+               return EFI_CARVE_NO_OVERLAP;
 
        /* We're overlapping with non-RAM, warn the caller if desired */
        if (overlap_only_ram && (map_desc->type != EFI_CONVENTIONAL_MEMORY))
-               return -1;
+               return EFI_CARVE_OVERLAPS_NONRAM;
 
        /* Sanitize carve_start and carve_end to lie within our bounds */
        carve_start = max(carve_start, map_start);
@@ -97,7 +99,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
 
                map_desc->physical_start = carve_end;
                map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT;
-               return 1;
+               return (carve_end - carve_start) >> EFI_PAGE_SHIFT;
        }
 
        /*
@@ -117,7 +119,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
        /* Shrink the map to [ map_start ... carve_start ] */
        map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT;
 
-       return 1;
+       return EFI_CARVE_LOOP_AGAIN;
 }
 
 uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
@@ -125,7 +127,11 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
 {
        struct list_head *lhandle;
        struct efi_mem_list *newlist;
-       bool do_carving;
+       bool carve_again;
+       uint64_t carved_pages = 0;
+
+       debug("%s: 0x%" PRIx64 " 0x%" PRIx64 " %d %s\n", __func__,
+             start, pages, memory_type, overlap_only_ram ? "yes" : "no");
 
        if (!pages)
                return start;
@@ -152,7 +158,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
 
        /* Add our new map */
        do {
-               do_carving = false;
+               carve_again = false;
                list_for_each(lhandle, &efi_mem) {
                        struct efi_mem_list *lmem;
                        int r;
@@ -160,14 +166,44 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
                        lmem = list_entry(lhandle, struct efi_mem_list, link);
                        r = efi_mem_carve_out(lmem, &newlist->desc,
                                              overlap_only_ram);
-                       if (r < 0) {
+                       switch (r) {
+                       case EFI_CARVE_OVERLAPS_NONRAM:
+                               /*
+                                * The user requested to only have RAM overlaps,
+                                * but we hit a non-RAM region. Error out.
+                                */
                                return 0;
-                       } else if (r) {
-                               do_carving = true;
+                       case EFI_CARVE_NO_OVERLAP:
+                               /* Just ignore this list entry */
+                               break;
+                       case EFI_CARVE_LOOP_AGAIN:
+                               /*
+                                * We split an entry, but need to loop through
+                                * the list again to actually carve it.
+                                */
+                               carve_again = true;
+                               break;
+                       default:
+                               /* We carved a number of pages */
+                               carved_pages += r;
+                               carve_again = true;
+                               break;
+                       }
+
+                       if (carve_again) {
+                               /* The list changed, we need to start over */
                                break;
                        }
                }
-       } while (do_carving);
+       } while (carve_again);
+
+       if (overlap_only_ram && (carved_pages != pages)) {
+               /*
+                * The payload wanted to have RAM overlaps, but we overlapped
+                * with an unallocated region. Error out.
+                */
+               return 0;
+       }
 
        /* Add our new map */
         list_add_tail(&newlist->link, &efi_mem);
@@ -303,6 +339,9 @@ efi_status_t efi_get_memory_map(unsigned long *memory_map_size,
        if (descriptor_size)
                *descriptor_size = sizeof(struct efi_mem_desc);
 
+       if (descriptor_version)
+               *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
+
        if (*memory_map_size < map_size)
                return EFI_BUFFER_TOO_SMALL;