From: Chali Anis <chalianis1@gmail.com>
To: Sascha Hauer <s.hauer@pengutronix.de>,
BAREBOX <barebox@lists.infradead.org>
Cc: Chali Anis <chalianis1@gmail.com>
Subject: [PATCH 15/15] efi: payload: bootm: remove redundant reallocations in image loader
Date: Fri, 19 Sep 2025 23:03:24 -0400 [thread overview]
Message-ID: <20250919-efi-loader-v1-15-dd8cdafb9067@gmail.com> (raw)
In-Reply-To: <20250919-efi-loader-v1-0-dd8cdafb9067@gmail.com>
The EFI payload loader used to copy OS images, initrds and FDTs into
freshly allocated EFI pages before handing them to LoadImage() or
installing configuration tables. This resulted in unnecessary memory
moves, extra allocations and longer boot times.
Rework the loader to:
- pass buffers from read_file() or FIT images directly to
BS->load_image() without intermediate memcpy
- drop efi_allocate_pages()/efi_free_pages() wrappers where not needed
- avoid duplicate allocations for initrd and FDT data
- free only the original buffer after execution/unload
This eliminates redundant reallocations, simplifies the code, and
reduces boot overhead. Boot flow is now more deterministic with fewer
allocation failures possible on memory-constrained systems.
Signed-off-by: Chali Anis <chalianis1@gmail.com>
---
efi/payload/bootm.c | 344 +++++++++++++++++++++-------------------------------
1 file changed, 136 insertions(+), 208 deletions(-)
diff --git a/efi/payload/bootm.c b/efi/payload/bootm.c
index 401aefe28188bb4335f73a8e259a16c605096626..6dabce60845e85965147d5492b2b12091469726a 100644
--- a/efi/payload/bootm.c
+++ b/efi/payload/bootm.c
@@ -37,51 +37,10 @@ struct efi_mem_resource {
size_t size;
} __attribute__ ((packed));
-struct efi_image_data {
- struct image_data *data;
-
- efi_handle_t handle;
- struct efi_loaded_image *loaded_image;
-
- struct efi_mem_resource image_res;
- struct efi_mem_resource oftree_res;
- struct efi_mem_resource *initrd_res;
-};
-
-
-static void *efi_allocate_pages(efi_physical_addr_t *mem,
- size_t size,
- enum efi_allocate_type allocate_type,
- enum efi_memory_type mem_type)
-{
- efi_status_t efiret;
-
- efiret = BS->allocate_pages(allocate_type, mem_type,
- DIV_ROUND_UP(size, EFI_PAGE_SIZE), mem);
- if (EFI_ERROR(efiret)) {
- errno = efi_errno(efiret);
- return NULL;
- }
-
- return efi_phys_to_virt(*mem);
-}
-
-static void efi_free_pages(void *_mem, size_t size)
-{
- efi_physical_addr_t mem = efi_virt_to_phys(_mem);
-
- if (mem_malloc_start() <= mem && mem < mem_malloc_end())
- free(_mem);
- else
- BS->free_pages(mem, DIV_ROUND_UP(size, EFI_PAGE_SIZE));
-}
-
-static int efi_load_file_image(const char *file,
- struct efi_loaded_image **loaded_image,
- efi_handle_t *h)
+static void *efi_load_file_image(const char *file,
+ struct efi_loaded_image **loaded_image,
+ efi_handle_t *h)
{
- efi_physical_addr_t mem;
- void *exe;
char *buf;
size_t size;
efi_handle_t handle;
@@ -90,19 +49,9 @@ static int efi_load_file_image(const char *file,
buf = read_file(file, &size);
if (!buf)
- return -ENOMEM;
-
- exe = efi_allocate_pages(&mem, size, EFI_ALLOCATE_ANY_PAGES,
- EFI_LOADER_CODE);
- if (!exe) {
- pr_err("Failed to allocate pages for image\n");
- ret = -ENOMEM;
- goto free_buf;
- }
-
- memcpy(exe, buf, size);
+ return ERR_PTR(-ENOMEM);
- efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe,
+ efiret = BS->load_image(false, efi_parent_image, efi_device_path, buf,
size, &handle);
if (EFI_ERROR(efiret)) {
ret = -efi_errno(efiret);
@@ -121,16 +70,12 @@ static int efi_load_file_image(const char *file,
}
*h = handle;
- free(buf);
- return 0;
+ return buf;
free_mem:
- efi_free_pages(exe, size);
-free_buf:
free(buf);
-
- return ret;
+ return ERR_PTR(ret);
}
static bool ramdisk_is_fit(struct image_data *data)
@@ -165,44 +110,31 @@ static bool fdt_is_fit(struct image_data *data)
data->fit_config, "fdt") > 0 : false;
}
-static int efi_load_os(struct efi_image_data *e)
+static void *efi_load_os(struct image_data *data,
+ struct efi_loaded_image **loaded_image,
+ efi_handle_t *handle)
{
efi_status_t efiret = EFI_SUCCESS;
- efi_physical_addr_t mem;
- size_t image_size = 0;
- void *image = NULL;
- void *vmem = NULL;
+ efi_handle_t h;
int ret = 0;
- if (!e->data->os_fit)
- return efi_load_file_image(e->data->os_file,
- &e->loaded_image, &e->handle);
-
- image = (void *)e->data->fit_kernel;
- image_size = e->data->fit_kernel_size;
+ if (!data->os_fit)
+ return efi_load_file_image(data->os_file,
+ loaded_image, handle);
- if (image_size <= 0 || !image)
- return -EINVAL;
+ if (data->fit_kernel_size <= 0 || !data->fit_kernel)
+ return ERR_PTR(-EINVAL);
- vmem = efi_allocate_pages(&mem, image_size, EFI_ALLOCATE_ANY_PAGES,
- EFI_LOADER_CODE);
- if (!vmem) {
- pr_err("Failed to allocate pages for image\n");
- return -ENOMEM;
- }
-
- memcpy(vmem, image, image_size);
-
- efiret = BS->load_image(false, efi_parent_image, efi_device_path, image,
- image_size, &e->handle);
+ efiret = BS->load_image(false, efi_parent_image, efi_device_path,
+ (void *)data->fit_kernel, data->fit_kernel_size, &h);
if (EFI_ERROR(efiret)) {
ret = -efi_errno(efiret);
pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
goto out_mem;
};
- efiret = BS->open_protocol(e->handle, &efi_loaded_image_protocol_guid,
- (void **)&e->loaded_image, efi_parent_image,
+ efiret = BS->open_protocol(h, &efi_loaded_image_protocol_guid,
+ (void **)loaded_image, efi_parent_image,
NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(efiret)) {
ret = -efi_errno(efiret);
@@ -210,172 +142,156 @@ static int efi_load_os(struct efi_image_data *e)
goto out_unload;
}
- e->image_res.base = mem;
- e->image_res.size = image_size;
+ *handle = h;
- return 0;
+ return (void *)data->fit_kernel;
-out_mem:
- efi_free_pages(vmem, image_size);
out_unload:
- BS->unload_image(e->handle);
- return ret;
+ BS->unload_image(h);
+out_mem:
+ return ERR_PTR(ret);
}
-static void efi_unload_os(struct efi_image_data *e)
+static void efi_unload_os(struct image_data *data,
+ void *image, efi_handle_t handle)
{
- BS->close_protocol(e->handle, &efi_loaded_image_protocol_guid,
+ BS->close_protocol(handle, &efi_loaded_image_protocol_guid,
efi_parent_image, NULL);
- BS->unload_image(e->handle);
- efi_free_pages(efi_phys_to_virt(e->image_res.base),
- e->image_res.size);
+ BS->unload_image(handle);
+
+ free(image);
}
-static int efi_load_ramdisk(struct efi_image_data *e)
+static int efi_load_ramdisk(struct image_data *data,
+ struct efi_mem_resource **initrd_res)
{
- void *vmem, *tmp = NULL;
- efi_physical_addr_t mem;
+ struct efi_mem_resource *res;
efi_status_t efiret = EFI_SUCCESS;
- const void *initrd;
unsigned long initrd_size;
+ void *initrd;
int ret;
- if (ramdisk_is_fit(e->data)) {
- ret = fit_open_image(e->data->os_fit, e->data->fit_config,
- "ramdisk", &initrd, &initrd_size);
+ if (ramdisk_is_fit(data)) {
+ ret = fit_open_image(data->os_fit, data->fit_config,
+ "ramdisk", (const void **)&initrd, &initrd_size);
if (ret) {
- pr_err("Cannot open ramdisk image in FIT image: %pe\n",
- ERR_PTR(ret));
+ pr_err("Cannot open ramdisk image in FIT image: %s\n",
+ strerror(ret));
return ret;
}
} else {
- if (!e->data->initrd_file)
+ if (!data->initrd_file)
return 0;
- pr_info("Loading ramdisk from '%s'\n", e->data->initrd_file);
- tmp = read_file(e->data->initrd_file, &initrd_size);
- if (!tmp || initrd_size <= 0) {
+ pr_info("Loading ramdisk from '%s'\n", data->initrd_file);
+ initrd = read_file(data->initrd_file, &initrd_size);
+ if (!initrd || initrd_size <= 0) {
pr_err("Failed to read initrd from file: %s\n",
- e->data->initrd_file);
+ data->initrd_file);
return -EINVAL;
}
- initrd = tmp;
}
efiret = BS->allocate_pool(EFI_LOADER_DATA,
sizeof(struct efi_mem_resource),
- (void **)&e->initrd_res);
- if (EFI_ERROR(efiret) || !e->initrd_res) {
+ (void **)&res);
+ if (EFI_ERROR(efiret) || !res) {
ret = -efi_errno(efiret);
pr_err("Failed to allocate initrd %s/n", efi_strerror(efiret));
goto free_mem;
}
- vmem = efi_allocate_pages(&mem, initrd_size,
- EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA);
- if (!vmem) {
- pr_err("Failed to allocate pages for initrd data: %s\n", strerror(errno));
- ret = -ENOMEM;
- goto free_pool;
- }
-
- memcpy(vmem, (void *)initrd, initrd_size);
- e->initrd_res->base = (uint64_t)mem;
- e->initrd_res->size = (uint64_t)initrd_size;
+ res->base = (uint64_t)efi_virt_to_phys(initrd);
+ res->size = (uint64_t)initrd_size;
if (IS_ENABLED(CONFIG_EFI_INITRD_INSTALL)) {
efiret = BS->install_configuration_table(
&efi_linux_initrd_media_guid,
- (void *)e->initrd_res);
+ (void *)res);
if (EFI_ERROR(efiret)) {
ret = -efi_errno(efiret);
pr_err("Failed to install INITRD %s/n",
efi_strerror(efiret));
- goto free_pages;
+ goto free_pool;
}
} else {
- ret = efi_initrd_register(vmem, initrd_size);
+ ret = efi_initrd_register(initrd, initrd_size);
if (ret) {
pr_err("Failed to register INITRD %s/n",
strerror(efiret));
- goto free_pages;
+ goto free_pool;
}
}
- free(tmp);
-
+ *initrd_res = res;
return 0;
-free_pages:
- efi_free_pages(vmem, initrd_size);
free_pool:
- BS->free_pool(e->initrd_res);
+ BS->free_pool(res);
free_mem:
- free(tmp);
+ free(initrd);
return ret;
}
-static void efi_unload_ramdisk(struct efi_image_data *e)
+static void efi_unload_ramdisk(struct image_data *data,
+ struct efi_mem_resource *initrd_res)
{
+ if (!initrd_res)
+ return;
+
if (IS_ENABLED(CONFIG_EFI_INITRD_INSTALL))
BS->install_configuration_table(
&efi_linux_initrd_media_guid, NULL);
else
efi_initrd_unregister();
- efi_free_pages(efi_phys_to_virt(e->initrd_res->base),
- e->initrd_res->size);
-
- BS->free_pool(e->initrd_res);
- e->initrd_res = NULL;
+ free(efi_phys_to_virt(initrd_res->base));
+ BS->free_pool(initrd_res);
+ initrd_res = NULL;
}
-static int efi_load_fdt(struct efi_image_data *e)
+static int efi_load_fdt(struct image_data *data, void **fdt)
{
- efi_status_t efiret = EFI_SUCCESS;
efi_physical_addr_t mem;
- void *vmem, *tmp = NULL;
- const void *of_tree;
+ efi_status_t efiret = EFI_SUCCESS;
+ void *of_tree, *vmem;
unsigned long of_size;
int ret;
- if (IS_ENABLED(CONFIG_EFI_FDT_FORCE))
- return 0;
-
- if (fdt_is_fit(e->data)) {
- ret = fit_open_image(e->data->os_fit, e->data->fit_config,
- "fdt", &of_tree, &of_size);
+ if (fdt_is_fit(data)) {
+ ret = fit_open_image(data->os_fit, data->fit_config,
+ "fdt", (const void **)&of_tree, &of_size);
if (ret) {
- pr_err("Cannot open FDT image in FIT image: %pe\n",
- ERR_PTR(ret));
+ pr_err("Cannot open FDT image in FIT image: %s\n",
+ strerror(ret));
return ret;
}
} else {
- if (!e->data->oftree_file)
+ if (!data->oftree_file)
return 0;
- pr_info("Loading devicetree from '%s'\n", e->data->oftree_file);
- tmp = read_file(e->data->oftree_file, &of_size);
- if (!tmp || of_size <= 0) {
+ pr_info("Loading devicetree from '%s'\n", data->oftree_file);
+ of_tree = read_file(data->oftree_file, &of_size);
+ if (!of_tree || of_size <= 0) {
pr_err("Failed to read initrd from file: %s\n",
- e->data->initrd_file);
+ data->initrd_file);
return -EINVAL;
}
- of_tree = tmp;
}
- vmem = efi_allocate_pages(&mem, SZ_128K,
- EFI_ALLOCATE_ANY_PAGES,
- EFI_ACPI_RECLAIM_MEMORY);
- if (!vmem) {
+ efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_ACPI_RECLAIM_MEMORY,
+ DIV_ROUND_UP(SZ_2M, EFI_PAGE_SIZE), &mem);
+ if (EFI_ERROR(efiret)) {
+ ret = -efi_errno(efiret);
pr_err("Failed to allocate pages for FDT\n");
- ret = -ENOMEM;
- goto free_file;
+ goto free_mem;
}
+ vmem = efi_phys_to_virt(mem);
memcpy(vmem, of_tree, of_size);
efiret = BS->install_configuration_table(&efi_fdt_guid,
@@ -383,83 +299,87 @@ static int efi_load_fdt(struct efi_image_data *e)
if (EFI_ERROR(efiret)) {
pr_err("Failed to install FDT %s/n", efi_strerror(efiret));
ret = -efi_errno(efiret);
- goto free_mem;
+ goto free_efi_mem;
}
- e->oftree_res.base = mem;
- e->oftree_res.size = SZ_128K;
-
- free(tmp);
-
+ *fdt = vmem;
return 0;
+free_efi_mem:
+ BS->free_pages(mem, DIV_ROUND_UP(SZ_2M, EFI_PAGE_SIZE));
free_mem:
- efi_free_pages(vmem, SZ_128K);
-free_file:
- free(tmp);
-
+ free(of_tree);
return ret;
}
-static void efi_unload_fdt(struct efi_image_data *e)
+static void efi_unload_fdt(void *fdt)
{
- if (IS_ENABLED(CONFIG_EFI_FDT_FORCE))
+ if (IS_ENABLED(CONFIG_EFI_FDT_FORCE) || !fdt)
return;
BS->install_configuration_table(&efi_fdt_guid, NULL);
-
- efi_free_pages(efi_phys_to_virt(e->oftree_res.base),
- e->oftree_res.size);
+ BS->free_pages(efi_virt_to_phys(fdt), SZ_2M);
}
static int do_bootm_efi_stub(struct image_data *data)
{
- struct efi_image_data e = { .data = data };
+ struct efi_mem_resource *initrd_res = NULL;
+ struct efi_loaded_image *loaded_image;
+ void *fdt = NULL, *image = NULL;
+ efi_handle_t handle;
enum filetype type;
int ret = 0;
- ret = efi_load_os(&e);
- if (ret)
- return ret;
+ image = efi_load_os(data, &loaded_image, &handle);
+ if (IS_ERR_OR_NULL(image))
+ return PTR_ERR(image);
- ret = efi_load_fdt(&e);
+ ret = efi_load_fdt(data, &fdt);
if (ret)
goto unload_os;
- ret = efi_load_ramdisk(&e);
+ ret = efi_load_ramdisk(data, &initrd_res);
if (ret)
goto unload_oftree;
- type = file_detect_type(e.loaded_image->image_base, PAGE_SIZE);
- ret = efi_execute_image(e.handle, e.loaded_image, type);
+ type = file_detect_type(loaded_image->image_base, PAGE_SIZE);
+ ret = efi_execute_image(handle, loaded_image, type);
if (ret)
goto unload_ramdisk;
return 0;
unload_ramdisk:
- if (e.initrd_res)
- efi_unload_ramdisk(&e);
+ efi_unload_ramdisk(data, initrd_res);
unload_oftree:
- efi_unload_fdt(&e);
+ efi_unload_fdt(fdt);
unload_os:
- efi_unload_os(&e);
+ efi_unload_os(data, image, handle);
return ret;
}
static int efi_app_execute(struct image_data *data)
{
- int ret;
- struct efi_image_data e = { .data = data };
+ struct efi_loaded_image *loaded_image;
+ efi_handle_t handle;
+ void *image;
enum filetype type;
+ int ret;
- ret = efi_load_file_image(data->os_file, &e.loaded_image, &e.handle);
+ image = efi_load_file_image(data->os_file, &loaded_image, &handle);
+ if (IS_ERR_OR_NULL(image))
+ return PTR_ERR(image);
+
+ type = file_detect_type(loaded_image->image_base, PAGE_SIZE);
+
+ ret = efi_execute_image(handle, loaded_image, type);
if (ret)
- return ret;
+ pr_err("EFI Application failed with error: %s\n",
+ strerror(ret));
- type = file_detect_type(e.loaded_image->image_base, PAGE_SIZE);
+ free(image);
- return efi_execute_image(e.handle, e.loaded_image, type);
+ return ret;
}
static struct image_handler efi_app_handle_tr = {
@@ -482,15 +402,23 @@ static struct image_handler efi_arm64_handle_tr = {
static int efi_execute(struct binfmt_hook *b, char *file, int argc, char **argv)
{
- int ret;
- efi_handle_t handle;
struct efi_loaded_image *loaded_image;
+ efi_handle_t handle;
+ void *image;
+ int ret;
+
+ image = efi_load_file_image(file, &loaded_image, &handle);
+ if (IS_ERR_OR_NULL(image))
+ return PTR_ERR(image);
- ret = efi_load_file_image(file, &loaded_image, &handle);
+ ret = efi_execute_image(handle, loaded_image, b->type);
if (ret)
- return ret;
+ pr_err("EFI Application failed with error: %s\n",
+ strerror(ret));
- return efi_execute_image(handle, loaded_image, b->type);
+ free(image);
+
+ return ret;
}
static struct binfmt_hook binfmt_efi_hook = {
@@ -532,13 +460,13 @@ static int efi_register_image_handler(void)
{
register_image_handler(&efi_app_handle_tr);
binfmt_register(&binfmt_efi_hook);
-
+
if (IS_ENABLED(CONFIG_X86)) {
register_image_handler(&non_efi_handle_linux_x86);
register_image_handler(&efi_x86_linux_handle_tr);
binfmt_register(&binfmt_x86_efi_hook);
}
-
+
if (IS_ENABLED(CONFIG_ARM64)) {
register_image_handler(&efi_arm64_handle_tr);
binfmt_register(&binfmt_arm64_efi_hook);
--
2.34.1
next prev parent reply other threads:[~2025-09-20 3:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-20 3:03 [PATCH 00/15] Implement efi loader to run barebox as efi payload app and then load efi stubed application/kernels chalianis1
2025-09-20 3:03 ` [PATCH 01/15] efi: payload: split image handling from legacy handover boot support chalianis1
2025-09-20 3:03 ` [PATCH 02/15] efi: payload: add support for efi stub boot chalianis1
2025-09-20 3:03 ` [PATCH 03/15] efi: payload: add support for fit image chalianis1
2025-09-20 3:03 ` [PATCH 04/15] efi: payload: make selectable without COMPILE_TEST chalianis1
2025-09-20 3:03 ` [PATCH 05/15] arm: efi: add a generic defconfig for v8 efi payload, Chali Anis
2025-09-20 3:03 ` [PATCH 06/15] efi: payload: initrd: implement efi initrd media protocol Chali Anis
2025-09-20 3:03 ` [PATCH 07/15] common: filetype: add x86 linux filetype Chali Anis
2025-09-20 3:03 ` [PATCH 08/15] efi: payload: early-mem: helps to correctly boot x86 linux Chali Anis
2025-09-20 3:03 ` [PATCH 09/15] efi: payload: bootm: add x86 efi stub boot support Chali Anis
2025-09-20 3:03 ` [PATCH 10/15] efi: payload: x86: enable the possibility to efi stub bootm for x86 Chali Anis
2025-09-20 3:03 ` [PATCH 11/15] malloc: tlsf: efi: add a fallback for allocate more memory when we are in efi Chali Anis
2025-09-20 3:03 ` [PATCH 12/15] configs: efi: arm64: x86: enable the use of efi malloc fallback Chali Anis
2025-09-20 3:03 ` [PATCH 13/15] efi: payload: earlymem: allocate only the barebox needs in term of memory Chali Anis
2025-09-20 3:03 ` [PATCH 14/15] ARM: cpu: allow selecting CPU_V7/CPU_V8 directly chalianis1
2025-09-20 3:03 ` Chali Anis [this message]
2025-09-22 7:37 ` [PATCH 00/15] Implement efi loader to run barebox as efi payload app and then load efi stubed application/kernels Ahmad Fatoum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250919-efi-loader-v1-15-dd8cdafb9067@gmail.com \
--to=chalianis1@gmail.com \
--cc=barebox@lists.infradead.org \
--cc=s.hauer@pengutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox