aboutsummaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_memory.c
diff options
context:
space:
mode:
authorAlexander Graf2018-09-16 17:05:29 +0200
committerAlexander Graf2018-09-23 21:55:30 +0200
commit7b05667ce23914f6989f8c2ade1ac96ce4ff4eb6 (patch)
treec23d4d7ec60a9bae0e71491d291d2b94c5a4eac3 /lib/efi_loader/efi_memory.c
parent79276eb2430d02c84a31fc5613e41aba05429184 (diff)
efi_loader: Merge memory map entries
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>
Diffstat (limited to 'lib/efi_loader/efi_memory.c')
-rw-r--r--lib/efi_loader/efi_memory.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 4f8cb545ad4..5bd4f4d7fc4 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -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