Skip to content
Snippets Groups Projects
Commit 74c16acc authored by Alexander Graf's avatar Alexander Graf Committed by Tom Rini
Browse files

efi_loader: Don't allocate from memory holes


When a payload calls our memory allocator with the exact address hint, we
happily allocate memory from completely unpopulated regions. Payloads however
expect this to only succeed if they would be allocating from free conventional
memory.

This patch makes the logic behind those checks a bit more obvious and ensures
that we always allocate from known good free conventional memory regions if we
want to allocate ram.

Reported-by: default avatarJonathan Gray <jsg@jsg.id.au>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent edcef3ba
No related branches found
No related tags found
No related merge requests found
...@@ -22,6 +22,10 @@ struct efi_mem_list { ...@@ -22,6 +22,10 @@ struct efi_mem_list {
struct efi_mem_desc desc; 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 */ /* This list contains all memory map items */
LIST_HEAD(efi_mem); LIST_HEAD(efi_mem);
...@@ -76,11 +80,11 @@ static int efi_mem_carve_out(struct efi_mem_list *map, ...@@ -76,11 +80,11 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
/* check whether we're overlapping */ /* check whether we're overlapping */
if ((carve_end <= map_start) || (carve_start >= map_end)) 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 */ /* We're overlapping with non-RAM, warn the caller if desired */
if (overlap_only_ram && (map_desc->type != EFI_CONVENTIONAL_MEMORY)) 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 */ /* Sanitize carve_start and carve_end to lie within our bounds */
carve_start = max(carve_start, map_start); carve_start = max(carve_start, map_start);
...@@ -95,7 +99,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map, ...@@ -95,7 +99,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
map_desc->physical_start = carve_end; map_desc->physical_start = carve_end;
map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT; map_desc->num_pages = (map_end - carve_end) >> EFI_PAGE_SHIFT;
return 1; return (carve_end - carve_start) >> EFI_PAGE_SHIFT;
} }
/* /*
...@@ -115,7 +119,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map, ...@@ -115,7 +119,7 @@ static int efi_mem_carve_out(struct efi_mem_list *map,
/* Shrink the map to [ map_start ... carve_start ] */ /* Shrink the map to [ map_start ... carve_start ] */
map_desc->num_pages = (carve_start - map_start) >> EFI_PAGE_SHIFT; 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, uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
...@@ -123,7 +127,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, ...@@ -123,7 +127,8 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
{ {
struct list_head *lhandle; struct list_head *lhandle;
struct efi_mem_list *newlist; struct efi_mem_list *newlist;
bool do_carving; bool carve_again;
uint64_t carved_pages = 0;
if (!pages) if (!pages)
return start; return start;
...@@ -150,7 +155,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, ...@@ -150,7 +155,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
/* Add our new map */ /* Add our new map */
do { do {
do_carving = false; carve_again = false;
list_for_each(lhandle, &efi_mem) { list_for_each(lhandle, &efi_mem) {
struct efi_mem_list *lmem; struct efi_mem_list *lmem;
int r; int r;
...@@ -158,14 +163,44 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, ...@@ -158,14 +163,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); lmem = list_entry(lhandle, struct efi_mem_list, link);
r = efi_mem_carve_out(lmem, &newlist->desc, r = efi_mem_carve_out(lmem, &newlist->desc,
overlap_only_ram); 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; return 0;
} else if (r) { case EFI_CARVE_NO_OVERLAP:
do_carving = true; /* 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; 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 */ /* Add our new map */
list_add_tail(&newlist->link, &efi_mem); list_add_tail(&newlist->link, &efi_mem);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment