efi_loader: Merge memory map entries
authorAlexander Graf <agraf@suse.de>
Sun, 16 Sep 2018 15:05:29 +0000 (17:05 +0200)
committerAlexander Graf <agraf@suse.de>
Sun, 23 Sep 2018 19:55:30 +0000 (21:55 +0200)
We currently do not combine memory entries that are adjacent and have
the same attributes. The problem with that is that our memory map can
easily grow multiple hundreds of entries in a simple UEFI Shell
environment.

So let's make sure we always combine all entries to make the memory
map as small as possible. That way every other piece of code that
loops through it should also gain some nice speed ups.

Signed-off-by: Alexander Graf <agraf@suse.de>
lib/efi_loader/efi_memory.c

index 4f8cb545ad445eb892fa34b3124f8d5427338829..5bd4f4d7fc49fbf90a4413687f148e57bacde1ea 100644 (file)
@@ -65,9 +65,54 @@ static int efi_mem_cmp(void *priv, struct list_head *a, struct list_head *b)
                return -1;
 }
 
+static uint64_t desc_get_end(struct efi_mem_desc *desc)
+{
+       return desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT);
+}
+
 static void efi_mem_sort(void)
 {
+       struct list_head *lhandle;
+       struct efi_mem_list *prevmem = NULL;
+       bool merge_again = true;
+
        list_sort(NULL, &efi_mem, efi_mem_cmp);
+
+       /* Now merge entries that can be merged */
+       while (merge_again) {
+               merge_again = false;
+               list_for_each(lhandle, &efi_mem) {
+                       struct efi_mem_list *lmem;
+                       struct efi_mem_desc *prev = &prevmem->desc;
+                       struct efi_mem_desc *cur;
+                       uint64_t pages;
+
+                       lmem = list_entry(lhandle, struct efi_mem_list, link);
+                       if (!prevmem) {
+                               prevmem = lmem;
+                               continue;
+                       }
+
+                       cur = &lmem->desc;
+
+                       if ((desc_get_end(cur) == prev->physical_start) &&
+                           (prev->type == cur->type) &&
+                           (prev->attribute == cur->attribute)) {
+                               /* There is an existing map before, reuse it */
+                               pages = cur->num_pages;
+                               prev->num_pages += pages;
+                               prev->physical_start -= pages << EFI_PAGE_SHIFT;
+                               prev->virtual_start -= pages << EFI_PAGE_SHIFT;
+                               list_del(&lmem->link);
+                               free(lmem);
+
+                               merge_again = true;
+                               break;
+                       }
+
+                       prevmem = lmem;
+               }
+       }
 }
 
 /** efi_mem_carve_out - unmap memory region