summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader/efi_memory.c')
-rw-r--r--lib/efi_loader/efi_memory.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index c82b53f336..8a1e249430 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -13,6 +13,7 @@
#include <malloc.h>
#include <asm/global_data.h>
#include <libfdt_env.h>
+#include <linux/list_sort.h>
#include <inttypes.h>
#include <watchdog.h>
@@ -27,6 +28,31 @@ struct efi_mem_list {
LIST_HEAD(efi_mem);
/*
+ * Sorts the memory list from highest address to lowest address
+ *
+ * When allocating memory we should always start from the highest
+ * address chunk, so sort the memory list such that the first list
+ * iterator gets the highest address and goes lower from there.
+ */
+static int efi_mem_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+ struct efi_mem_list *mema = list_entry(a, struct efi_mem_list, link);
+ struct efi_mem_list *memb = list_entry(b, struct efi_mem_list, link);
+
+ if (mema->desc.physical_start == memb->desc.physical_start)
+ return 0;
+ else if (mema->desc.physical_start < memb->desc.physical_start)
+ return 1;
+ else
+ return -1;
+}
+
+static void efi_mem_sort(void)
+{
+ list_sort(NULL, &efi_mem, efi_mem_cmp);
+}
+
+/*
* Unmaps all memory occupied by the carve_desc region from the
* list entry pointed to by map.
*
@@ -142,6 +168,9 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
/* Add our new map */
list_add_tail(&newlist->link, &efi_mem);
+ /* And make sure memory is listed in descending order */
+ efi_mem_sort();
+
return start;
}