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


Reply via email to