this will fix the OOM issues for when barebox is running on top of efi. the OOM were unpredictble since we can't determine the size required in advance for initrd or kernel. with this patch we don't need anymore to increase memory in efi early mem, we allocate only what barebox needs to relocate itself and have what it needs to manage peripherls, at any OOM we fallback to efi to give us more memory. So we get a more deterministic behaviour and more generic efi payload and finally a huge speedup for the boot time. and the most important a clean code.
Signed-off-by: Chali Anis <chalian...@gmail.com> --- common/Kconfig | 9 ++++++ common/Makefile | 1 + common/efi_malloc.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/tlsf_malloc.c | 22 +++++++++++++-- include/malloc.h | 19 +++++++++++++ 5 files changed, 129 insertions(+), 2 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index eb2fb1da1e0919b6e7d5e868c48ad2e195cd8aa8..5e2251ff7821f14556b19816a51eb8d7e9133a6f 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -317,6 +317,15 @@ config EXPERIMENTAL bool prompt "Prompt for experimental code" +config MALLOC_EFI + bool "efi malloc fallback" + depends on EFI_PAYLOAD + help + select this option to use efi malloc fallback, it will permit, + when we use barebox as an efi payload to automaticlly allocate + more memory from efi as needed, permits to be more resilient with + OOM and support what ever we have to boot or execute as efi app. + choice prompt "malloc implementation" default MALLOC_TLSF diff --git a/common/Makefile b/common/Makefile index d501a6a2755a113fac3ac632806d4a92b741d6e2..aa693b4c31b66aecb76192579466972fb8c351b3 100644 --- a/common/Makefile +++ b/common/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o tlsf.o calloc.o KASAN_SANITIZE_tlsf.o := n obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o calloc.o +obj-$(CONFIG_MALLOC_EFI) += efi_malloc.o obj-y += malloc.o obj-$(CONFIG_MEMINFO) += meminfo.o obj-$(CONFIG_MENU) += menu.o diff --git a/common/efi_malloc.c b/common/efi_malloc.c new file mode 100644 index 0000000000000000000000000000000000000000..fcd97794f2d6e08d41acd9f2a4d4fc0252b6caf2 --- /dev/null +++ b/common/efi_malloc.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2013 Sascha Hauer <s.ha...@pengutronix.de> + */ +#include <linux/sizes.h> +#include <common.h> +#include <malloc.h> +#include <efi.h> +#include <efi/efi-util.h> +#include <string.h> +#include <errno.h> + +struct alloc_header { + size_t size; /* requested size */ +}; + +void *efi_malloc(size_t size) +{ + efi_status_t efiret; + efi_physical_addr_t mem; + struct alloc_header *hdr; + size_t pages; + + if (!size) + return ZERO_SIZE_PTR; + + pages = DIV_ROUND_UP(size, EFI_PAGE_SIZE); + efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA, + pages, &mem); + if (EFI_ERROR(efiret)) { + errno = efi_errno(efiret); + return NULL; + } + + hdr = (struct alloc_header *)efi_phys_to_virt(mem); + hdr->size = size; + return (void *)(hdr + 1); +} + +void efi_free(void *ptr) +{ + efi_physical_addr_t phys; + struct alloc_header *hdr; + + if (!ptr) + return; + + hdr = (struct alloc_header *)ptr - 1; + phys = efi_virt_to_phys(hdr); + BS->free_pages(phys, DIV_ROUND_UP(hdr->size, EFI_PAGE_SIZE)); +} + +void *efi_realloc(void *ptr, size_t size) +{ + struct alloc_header *hdr; + void *n_mem; + size_t old_sz; + + if (!ptr) + return efi_malloc(size); + + if (!size) { + efi_free(ptr); + return NULL; + } + + hdr = (struct alloc_header *)ptr - 1; + old_sz = hdr->size; + + n_mem = efi_malloc(size); + if (!n_mem) { + errno = ENOMEM; + return NULL; + } + + memcpy(n_mem, ptr, (old_sz < size) ? old_sz : size); + efi_free(ptr); + + return n_mem; +} diff --git a/common/tlsf_malloc.c b/common/tlsf_malloc.c index 6e9d48af26bbf05573fda04f616412c895342593..25ae40e455528a318fc150dba4ea7bc2ce27f3e3 100644 --- a/common/tlsf_malloc.c +++ b/common/tlsf_malloc.c @@ -6,6 +6,8 @@ */ #include <malloc.h> +#include <efi.h> +#include <memory.h> #include <string.h> #include <stdio.h> @@ -29,8 +31,12 @@ void *malloc(size_t bytes) void *mem; mem = tlsf_malloc(tlsf_mem_pool, bytes); - if (!mem) + if (!mem) { + if (IS_ENABLED(CONFIG_MALLOC_EFI)) + return efi_malloc(bytes); + errno = ENOMEM; + } return mem; } @@ -38,6 +44,14 @@ EXPORT_SYMBOL(malloc); void free(void *mem) { + if (IS_ENABLED(CONFIG_MALLOC_EFI)) { + if (efi_virt_to_phys(mem) < mem_malloc_start() && + efi_virt_to_phys(mem) > mem_malloc_end()) { + efi_free(mem); + return; + } + } + tlsf_free(tlsf_mem_pool, mem); } EXPORT_SYMBOL(free); @@ -51,8 +65,12 @@ EXPORT_SYMBOL(malloc_usable_size); void *realloc(void *oldmem, size_t bytes) { void *mem = tlsf_realloc(tlsf_mem_pool, oldmem, bytes); - if (!mem) + if (!mem) { + if (IS_ENABLED(CONFIG_MALLOC_EFI)) + return efi_realloc(oldmem, bytes); + errno = ENOMEM; + } return mem; } diff --git a/include/malloc.h b/include/malloc.h index 35551250324ee1d3c8ddc06f49a06ce07d2855bd..2294d129838829955ffc08c5ecb9df91d05073c9 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -24,6 +24,25 @@ #ifdef CONFIG_MALLOC_TLSF void *malloc_add_pool(void *mem, size_t bytes); #endif +void *efi_malloc(size_t size); +void efi_free(void *ptr); +void *efi_realloc(void *ptr, size_t size); +#ifdef MALLOC_EFI +static inline void *efi_malloc(size_t size) +{ + errno = -ENOMEM; + return NULL; +} + +static inline void efi_free(void *ptr) {} + +static inline void *efi_realloc(void *ptr, size_t size) +{ + errno = -ENOMEM; + return NULL; +} +#else +#endif #if IN_PROPER void *malloc(size_t) __alloc_size(1); -- 2.34.1