With global.bootm.image pointing at a raw partition, bootm loads all of it, and hands the trailing data to efiloader_load_image() as part of the image.
Read the PE headers first and load only as much as efi_pe_image_size() reports. This saves on boot time, since only the actually needed data is loaded. Files whose headers do not parse are loaded in full as before. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Johannes Schneider <[email protected]> --- efi/loader/bootm.c | 56 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/efi/loader/bootm.c b/efi/loader/bootm.c index 425e61fd70..18539565fd 100644 --- a/efi/loader/bootm.c +++ b/efi/loader/bootm.c @@ -35,6 +35,8 @@ #include <efi/error.h> #include <efi/initrd.h> #include <efi/devicepath.h> +#include <efi/loader/pe.h> +#include <loadable.h> /** * copy_fdt() - Copy the device tree to a new location available to EFI @@ -193,6 +195,48 @@ static efi_status_t efi_install_initrd(struct image_data *data, return EFI_SUCCESS; } +/* The image may sit in a much larger partition: load only the image */ +static const struct resource *efi_load_os(struct image_data *data, + resource_size_t start, + resource_size_t end) +{ + size_t len = SZ_64K, size = 0; + struct resource *res; + ssize_t now; + void *hdr; + + if (data->os_res || !data->os || loadable_count(data->os) > 1) + return bootm_load_os(data, start, end); + + hdr = xmalloc(len); + now = loadable_extract_into_buf(data->os, hdr, len, 0, + LOADABLE_EXTRACT_PARTIAL); + if (now > 0) + size = efi_pe_image_size(hdr, now); + free(hdr); + + if (!size) + return bootm_load_os(data, start, end); + if (size > end - start + 1) + return ERR_PTR(-ENOSPC); + + res = request_sdram_region("kernel", start, size, MEMTYPE_LOADER_CODE, + MEMATTRS_RWX); + if (!res) + return ERR_PTR(-EBUSY); + + now = loadable_extract_into_buf(data->os, (void *)res->start, size, 0, + LOADABLE_EXTRACT_PARTIAL); + if (now != size) { + release_sdram_region(res); + return ERR_PTR(now < 0 ? now : -EIO); + } + + data->os_res = res; + + return res; +} + static int efi_loader_bootm(struct image_data *data) { const struct resource *os_res; @@ -208,13 +252,20 @@ static int efi_loader_bootm(struct image_data *data) int ret = 0; void *fdt; int flags = 0; + size_t size; memory_bank_first_find_space(&start, &end); - os_res = bootm_load_os(data, start, end); + os_res = efi_load_os(data, start, end); if (IS_ERR(os_res)) return PTR_ERR(os_res); + size = efi_pe_file_size((void *)os_res->start, resource_size(os_res)); + if (!size) { + pr_err("%s is not a PE image\n", data->os_file); + return -EINVAL; + } + if (filetype_is_linux_efi_image(data->kernel_type)) { const char *options; @@ -262,8 +313,7 @@ static int efi_loader_bootm(struct image_data *data) flags |= EFI_DRYRUN; efiret = efiloader_load_image(false, efi_root, file_path, - (void *)os_res->start, - resource_size(os_res), &handle); + (void *)os_res->start, size, &handle); if (efiret != EFI_SUCCESS) { pr_err("Loading image failed\n"); goto out; -- 2.43.0
