aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2016-03-30 16:38:29 +0200
committerTom Rini <trini@konsulko.com>2016-04-01 17:18:06 -0400
commit38ce65e1fed1cd5962add9b746ea70e49586b54a (patch)
tree4c2477eb5055977ad845cafc4836c1e39ec50249
parent41582e2e77b6fb078db98d7c0765be133a766f81 (diff)
downloadu-boot-38ce65e1fed1cd5962add9b746ea70e49586b54a.zip
u-boot-38ce65e1fed1cd5962add9b746ea70e49586b54a.tar.gz
u-boot-38ce65e1fed1cd5962add9b746ea70e49586b54a.tar.bz2
efi_loader: Always allocate the highest available address
Some EFI applications (grub2) expect that an allocation always returns the highest available memory address for the given size. Without this, we may run into situations where the initrd gets allocated at a lower address than the kernel. This patch fixes booting in such situations for me. Signed-off-by: Alexander Graf <agraf@suse.de>
-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 c82b53f..8a1e249 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;
}