diff options
Diffstat (limited to 'lib/efi_loader/efi_memory.c')
-rw-r--r-- | lib/efi_loader/efi_memory.c | 85 |
1 files changed, 69 insertions, 16 deletions
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5bd4f4d7fc..4bb517473e 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -11,6 +11,7 @@ #include <mapmem.h> #include <watchdog.h> #include <linux/list_sort.h> +#include <linux/sizes.h> DECLARE_GLOBAL_DATA_PTR; @@ -294,6 +295,12 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr) { struct list_head *lhandle; + /* + * Prealign input max address, so we simplify our matching + * logic below and can just reuse it as return pointer. + */ + max_addr &= ~EFI_PAGE_MASK; + list_for_each(lhandle, &efi_mem) { struct efi_mem_list *lmem = list_entry(lhandle, struct efi_mem_list, link); @@ -378,7 +385,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, /* Reserve that map in our memory maps */ ret = efi_add_memory_map(addr, pages, memory_type, true); if (ret == addr) { - *memory = (uintptr_t)map_sysmem(addr, len); + *memory = addr; } else { /* Map would overlap, bail out */ r = EFI_OUT_OF_RESOURCES; @@ -391,7 +398,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, void *efi_alloc(uint64_t len, int memory_type) { uint64_t ret = 0; - uint64_t pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + uint64_t pages = efi_size_in_pages(len); efi_status_t r; r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, pages, @@ -412,12 +419,11 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) { uint64_t r = 0; - uint64_t addr = map_to_sysmem((void *)(uintptr_t)memory); - r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false); + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); /* Merging of adjacent free regions is missing */ - if (r == addr) + if (r == memory) return EFI_SUCCESS; return EFI_NOT_FOUND; @@ -435,8 +441,8 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) { efi_status_t r; struct efi_pool_allocation *alloc; - u64 num_pages = (size + sizeof(struct efi_pool_allocation) + - EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 num_pages = efi_size_in_pages(size + + sizeof(struct efi_pool_allocation)); if (!buffer) return EFI_INVALID_PARAMETER; @@ -545,17 +551,51 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, __weak void efi_add_known_memory(void) { + u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK; int i; + /* Fix for 32bit targets with ram_top at 4G */ + if (!ram_top) + ram_top = 0x100000000ULL; + /* Add RAM */ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; - u64 start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; - u64 pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 ram_end, ram_start, pages; + + ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0); + ram_end = ram_start + gd->bd->bi_dram[i].size; + + /* Remove partial pages */ + ram_end &= ~EFI_PAGE_MASK; + ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; + + if (ram_end <= ram_start) { + /* Invalid mapping, keep going. */ + continue; + } + + pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT; + + efi_add_memory_map(ram_start, pages, + EFI_CONVENTIONAL_MEMORY, false); - efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY, - false); + /* + * Boards may indicate to the U-Boot memory core that they + * can not support memory above ram_top. Let's honor this + * in the efi_loader subsystem too by declaring any memory + * above ram_top as "already occupied by firmware". + */ + if (ram_top < ram_start) { + /* ram_top is before this region, reserve all */ + efi_add_memory_map(ram_start, pages, + EFI_BOOT_SERVICES_DATA, true); + } else if ((ram_top >= ram_start) && (ram_top < ram_end)) { + /* ram_top is inside this region, reserve parts */ + pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT; + + efi_add_memory_map(ram_top, pages, + EFI_BOOT_SERVICES_DATA, true); + } } } @@ -563,6 +603,7 @@ __weak void efi_add_known_memory(void) static void add_u_boot_and_runtime(void) { unsigned long runtime_start, runtime_end, runtime_pages; + unsigned long runtime_mask = EFI_PAGE_MASK; unsigned long uboot_start, uboot_pages; unsigned long uboot_stack_size = 16 * 1024 * 1024; @@ -571,10 +612,22 @@ static void add_u_boot_and_runtime(void) uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT; efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false); - /* Add Runtime Services */ - runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK; +#if defined(__aarch64__) + /* + * Runtime Services must be 64KiB aligned according to the + * "AArch64 Platforms" section in the UEFI spec (2.7+). + */ + + runtime_mask = SZ_64K - 1; +#endif + + /* + * Add Runtime Services. We mark surrounding boottime code as runtime as + * well to fulfill the runtime alignment constraints but avoid padding. + */ + runtime_start = (ulong)&__efi_runtime_start & ~runtime_mask; runtime_end = (ulong)&__efi_runtime_stop; - runtime_end = (runtime_end + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; + runtime_end = (runtime_end + runtime_mask) & ~runtime_mask; runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT; efi_add_memory_map(runtime_start, runtime_pages, EFI_RUNTIME_SERVICES_CODE, false); |