summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2024-03-04 19:58:58 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2024-03-05 16:28:05 +0100
commit63c4468ff1b1cb82b753e61151175bce46185ed3 (patch)
tree065937e71e48fef3d08918d4fd8f211de6252ec5
parent761f51b69966202a0e8cb06723195b0eb69bbd98 (diff)
downloadbarebox-63c4468ff1b1.tar.gz
barebox-63c4468ff1b1.tar.xz
efi: payload: image: allocate image via loader if it exceeds malloc area
barebox allocates at maximum 256M for its own use when running as EFI payload. With bigger kernel images and initrds, this may exceed the space barebox has available, especially if decompression needs to happen within barebox. In that case, instead of failing with -ENOMEM, let's ask the EFI firmware for a suitably sized buffer and read into that if the allocation succeeds. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Link: https://lore.barebox.org/20240304190038.3486881-14-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--efi/payload/image.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/efi/payload/image.c b/efi/payload/image.c
index 8d29bf9bb4..b7f4b7560b 100644
--- a/efi/payload/image.c
+++ b/efi/payload/image.c
@@ -76,6 +76,51 @@ struct linux_kernel_header {
uint32_t handover_offset; /** */
} __attribute__ ((packed));
+static void *efi_read_file(const char *file, size_t *size)
+{
+ efi_physical_addr_t mem;
+ efi_status_t efiret;
+ struct stat s;
+ char *buf;
+ ssize_t ret;
+
+ buf = read_file(file, size);
+ if (buf || errno != ENOMEM)
+ return buf;
+
+ ret = stat(file, &s);
+ if (ret)
+ return NULL;
+
+ efiret = BS->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_LOADER_CODE,
+ DIV_ROUND_UP(s.st_size, EFI_PAGE_SIZE),
+ &mem);
+ if (EFI_ERROR(efiret)) {
+ errno = efi_errno(efiret);
+ return NULL;
+ }
+
+ buf = (void *)mem;
+
+ ret = read_file_into_buf(file, buf, s.st_size);
+ if (ret < 0)
+ return NULL;
+
+ *size = ret;
+ return buf;
+}
+
+static void efi_free_file(void *_mem, size_t size)
+{
+ efi_physical_addr_t mem = (efi_physical_addr_t)_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_image(const char *file, efi_loaded_image_t **loaded_image,
efi_handle_t *h)
{
@@ -84,7 +129,7 @@ static int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
efi_handle_t handle;
efi_status_t efiret = EFI_SUCCESS;
- exe = read_file(file, &size);
+ exe = efi_read_file(file, &size);
if (!exe)
return -errno;
@@ -106,7 +151,7 @@ static int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
*h = handle;
out:
- free(exe);
+ efi_free_file(exe, size);
return -efi_errno(efiret);
}